├── .gitignore ├── AsyncPayments ├── __init__.py ├── aaio │ ├── __init__.py │ ├── api.py │ └── models.py ├── cryptoBot │ ├── __init__.py │ ├── api.py │ └── models.py ├── cryptomus │ ├── __init__.py │ ├── api.py │ └── models.py ├── crystalPay │ ├── __init__.py │ ├── api.py │ └── models.py ├── exceptions │ ├── __init__.py │ └── exceptions.py ├── freeKassa │ ├── __init__.py │ ├── api.py │ └── models.py ├── lolz │ ├── __init__.py │ ├── api.py │ └── models.py ├── payok │ ├── __init__.py │ ├── api.py │ └── models.py ├── requests.py ├── ruKassa │ ├── __init__.py │ ├── api.py │ └── models.py └── xrocket │ ├── __init__.py │ ├── api.py │ └── models.py ├── LICENSE ├── README.md └── pyproject.toml /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | 3 | .venv/ 4 | venv/ 5 | env/ 6 | 7 | build/ 8 | dist/ 9 | 10 | *.egg-info/ 11 | 12 | .github 13 | 14 | .idea -------------------------------------------------------------------------------- /AsyncPayments/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/I-ToSa-I/AsyncPayments/fc34c6b1fc94424103b281e6a8ec299309ea50af/AsyncPayments/__init__.py -------------------------------------------------------------------------------- /AsyncPayments/aaio/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import AsyncAaio -------------------------------------------------------------------------------- /AsyncPayments/aaio/api.py: -------------------------------------------------------------------------------- 1 | from ..requests import RequestsClient 2 | from .models import Order, OrderMethod, WithdrawalMethod, CreateWithdrawalInfo, Withdrawal, Balance 3 | from typing import Optional, Union, List 4 | from urllib.parse import urlencode 5 | 6 | import hashlib 7 | 8 | 9 | class AsyncAaio(RequestsClient): 10 | API_HOST: str = "https://aaio.so" 11 | 12 | def __init__(self, apikey: str, shopid: str, secretkey: str) -> None: 13 | ''' 14 | Initialize Aaio API client 15 | :param apikey: Your API Key 16 | :param shopid: Your Shop ID 17 | :param secretkey: Your Secretkey №1 18 | ''' 19 | super().__init__() 20 | self.__api_key = apikey 21 | self.__shop_id = shopid 22 | self.__secret_key = secretkey 23 | self.__headers = { 24 | "Accept": "application/json", 25 | "X-Api-Key": self.__api_key 26 | } 27 | self.__post_method = "POST" 28 | self.__payment_name = "aaio" 29 | self.check_values() 30 | 31 | def check_values(self): 32 | if not self.__secret_key or not self.__shop_id or not self.__api_key: 33 | raise ValueError('No SecretKey, ApiKey or ShopID specified') 34 | 35 | def __create_sign(self, amount: Union[float, int], currency: str, order_id: str) -> str: 36 | params_for_sing = ':'.join(map( 37 | str, 38 | [self.__shop_id, amount, currency, self.__secret_key, order_id]) 39 | ) 40 | 41 | return hashlib.sha256(params_for_sing.encode('utf-8')).hexdigest() 42 | 43 | async def create_payment_url( 44 | self, 45 | amount: float, 46 | order_id: Union[int, str], 47 | currency: Optional[str] = 'RUB', 48 | method: Optional[str] = None, 49 | desc: Optional[str] = None, 50 | email: Optional[str] = None, 51 | lang: Optional[str] = None, 52 | referal: Optional[str] = None, 53 | us_key: Optional[str] = None, 54 | ) -> str: 55 | 56 | """Generate payment url. 57 | 58 | Docs: https://wiki.aaio.so/priem-platezhei/sozdanie-zakaza 59 | 60 | :param amount: Order amount. 61 | :param order_id: Order number, which unique in your system, up to 16 characters, without spaces (aA-zZ, 0-9, :, -, _, [, ] , |) 62 | :param currency: Currency. Default to 'RUB' (RUB, UAH, EUR, USD) 63 | :param method: Payment Aaio system code name 64 | :param desc: Order description 65 | :param email: Buyer mail 66 | :param lang: Interface language. Default to 'ru' (ru, en) 67 | :param referal: Referral code 68 | :param us_key: Parameter that you want to get in the notification""" 69 | 70 | params = { 71 | 'merchant_id': self.__shop_id, 72 | 'amount': amount, 73 | 'order_id': order_id, 74 | 'currency': currency, 75 | 'method': method, 76 | 'desc': desc, 77 | 'email': email, 78 | 'lang': lang, 79 | 'referal': referal, 80 | 'us_key': us_key, 81 | 'sign': self.__create_sign(amount, currency, order_id), 82 | } 83 | 84 | self._delete_empty_fields(params) 85 | 86 | headers = self.__headers 87 | headers["Content-Type"] = "application/x-www-form-urlencoded" 88 | response = await self._request(self.__payment_name, self.__post_method, f"{self.API_HOST}/merchant/get_pay_url", headers=headers, data=urlencode(params)) 89 | 90 | return response['url'] 91 | 92 | async def get_balance(self) -> Balance: 93 | """Get available, referal and hold balance. 94 | 95 | Docs: https://wiki.aaio.so/api/poluchenie-balansa""" 96 | 97 | url = f'{self.API_HOST}/api/balance' 98 | 99 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 100 | 101 | return Balance(**response) 102 | 103 | async def get_order_info(self, 104 | order_id: Union[int, str] 105 | ) -> Order: 106 | 107 | """Get information about an order by OrderID. 108 | 109 | Docs: https://wiki.aaio.so/api/informaciya-o-zakaze 110 | 111 | :param order_id: OrderID (in your system)""" 112 | 113 | url = f'{self.API_HOST}/api/info-pay' 114 | 115 | params = { 116 | 'merchant_id': self.__shop_id, 117 | 'order_id': order_id, 118 | } 119 | 120 | self._delete_empty_fields(params) 121 | 122 | response = await self._request(self.__payment_name, self.__post_method, url, data=params, headers=self.__headers) 123 | 124 | return Order(**response) 125 | 126 | async def get_withdrawal_methods(self, 127 | method: Optional[str] = None 128 | ) -> Union[List[WithdrawalMethod], WithdrawalMethod]: 129 | 130 | """Get available methods for withdrawal. 131 | 132 | If method is None -> return dict with all methods. 133 | 134 | If a specific method -> return info about only this method. 135 | 136 | Docs: https://wiki.aaio.so/api/dostupnye-metody-dlya-vyvoda-sredstv 137 | 138 | :param method: Specific method. Default is None""" 139 | 140 | url = f'{self.API_HOST}/api/methods-payoff' 141 | 142 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 143 | 144 | if method is not None: 145 | return WithdrawalMethod(**response['list'][method]) 146 | return [WithdrawalMethod(**method) for method in response["list"].values()] 147 | 148 | async def get_order_methods(self, 149 | method: Optional[str] = None 150 | ) -> Union[List[OrderMethod], OrderMethod]: 151 | 152 | """Get available methods for order. 153 | 154 | If method is None -> return dict with all methods. 155 | 156 | If a specific method -> return info about only this method. 157 | 158 | Docs: https://wiki.aaio.so/api/dostupnye-metody-dlya-sozdaniya-zakaza 159 | 160 | :param method: Specific method. Default is None""" 161 | 162 | url = f'{self.API_HOST}/api/methods-pay' 163 | 164 | params = { 165 | 'merchant_id': self.__shop_id, 166 | } 167 | 168 | response = await self._request(self.__payment_name, self.__post_method, url, data=params, headers=self.__headers) 169 | 170 | if method is not None: 171 | return OrderMethod.model_validate(response['list'][method]) 172 | return [OrderMethod(**method) for method in response["list"].values()] 173 | 174 | async def get_withdrawal_info(self, 175 | my_id: Union[int, str], 176 | ) -> Withdrawal: 177 | 178 | """Get information about a withdrawal by WithdrawalID. 179 | 180 | Docs: https://wiki.aaio.so/api/informaciya-o-zayavke-na-vyvod-sredstv 181 | 182 | :param my_id: WithdrawalID (in your system)""" 183 | 184 | url = f'{self.API_HOST}/api/info-payoff' 185 | 186 | params = { 187 | 'my_id': my_id, 188 | } 189 | 190 | response = await self._request(self.__payment_name, self.__post_method, url, data=params, headers=self.__headers) 191 | 192 | return Withdrawal(**response) 193 | 194 | async def create_withdrawal(self, 195 | my_id: Union[int, str], 196 | method: str, 197 | amount: float, 198 | wallet: str, 199 | commission_type: Optional[int] = 0 200 | ) -> CreateWithdrawalInfo: 201 | 202 | """Create withdrawal. 203 | 204 | Docs: https://wiki.aaio.so/api/vyvod-sredstv 205 | 206 | :param my_id: WithdrawalID (in your system) 207 | :param method: Specific method for withdrawal 208 | :param amount: Withdrawal amount 209 | :param wallet: Wallet or number for withdrawal (Without +, " ", and separators) 210 | :param commission_type: Withdrawal commission type. Default to 0 (from the payment amount)""" 211 | 212 | url = f'{self.API_HOST}/api/create-payoff' 213 | 214 | params = { 215 | 'my_id': my_id, 216 | 'method': method, 217 | 'amount': amount, 218 | 'wallet': wallet, 219 | 'commission_type': commission_type, 220 | } 221 | 222 | response = await self._request(self.__payment_name, self.__post_method, url, data=params, headers=self.__headers) 223 | 224 | return CreateWithdrawalInfo(**response) -------------------------------------------------------------------------------- /AsyncPayments/aaio/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import Union, Optional 3 | 4 | 5 | class Balance(BaseModel): 6 | balance: float 7 | referral: float 8 | hold: float 9 | 10 | class Order(BaseModel): 11 | id: str 12 | order_id: Union[int, str] 13 | desc: str 14 | merchant_id: str 15 | merchant_domain: str 16 | method: Optional[str] = None 17 | amount: Union[int, float] 18 | currency: str 19 | profit: Optional[float] = None 20 | commission: Optional[float] = None 21 | commission_client: Optional[float] = None 22 | commission_type: Optional[str] = None 23 | email: Optional[str] = None 24 | status: str 25 | date: str 26 | expired_date: str 27 | complete_date: Optional[str] = None 28 | us_vars: Optional[Union[dict, str, list]] = None 29 | 30 | class OrderMethodCurrencies(BaseModel): 31 | RUB: float 32 | UAH: float 33 | USD: float 34 | EUR: float 35 | 36 | class OrderMethod(BaseModel): 37 | name: str 38 | min: OrderMethodCurrencies 39 | max: OrderMethodCurrencies 40 | commission_percent: float 41 | 42 | class Withdrawal(BaseModel): 43 | id: str 44 | my_id: Union[int, str] 45 | method: str 46 | wallet: str 47 | amount: float 48 | amount_down: float 49 | commission: float 50 | commission_type: int 51 | status: str 52 | cancel_message: Optional[str] = None 53 | date: str 54 | complete_date: Optional[str] = None 55 | 56 | class WithdrawalMethod(BaseModel): 57 | name: str 58 | min: float 59 | max: float 60 | commission_percent: float 61 | commission_sum: float 62 | 63 | class CreateWithdrawalInfo(BaseModel): 64 | id: str 65 | my_id: Union[str, int] 66 | method: str 67 | wallet: str 68 | amount: float 69 | amount_in_currency: float 70 | amount_currency: str 71 | amount_rate: float 72 | amount_down: float 73 | commission: float 74 | commission_type: int 75 | status: str -------------------------------------------------------------------------------- /AsyncPayments/cryptoBot/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import AsyncCryptoBot -------------------------------------------------------------------------------- /AsyncPayments/cryptoBot/api.py: -------------------------------------------------------------------------------- 1 | from ..requests import RequestsClient 2 | from typing import Optional, Union, List 3 | from .models import Invoice, MeInfo, Transfer, Balance, Check, ExchangeRate, Currency 4 | 5 | 6 | class AsyncCryptoBot(RequestsClient): 7 | API_HOST: str = "https://t.me/Cryptobot" 8 | 9 | def __init__(self, token: str, is_testnet: bool = False) -> None: 10 | """ 11 | Initialize CryptoBot API client 12 | :param token: Your Token 13 | :param is_testnet: Optional. True - Testnet is on. False - Testnet is off. Default to False. 14 | """ 15 | super().__init__() 16 | self.__token = token 17 | self.__headers = { 18 | 'Crypto-Pay-API-Token': self.__token, 19 | } 20 | if is_testnet: 21 | self.__base_url = "https://testnet-pay.crypt.bot/api" 22 | else: 23 | self.__base_url = "https://pay.crypt.bot/api" 24 | self.__post_method = "POST" 25 | self.__payment_name = "cryptoBot" 26 | self.check_values() 27 | 28 | def check_values(self): 29 | if not self.__token: 30 | raise ValueError('No Token specified') 31 | 32 | async def get_me(self) -> MeInfo: 33 | """Use this method to test your app's authentication token. Requires no parameters. On success, returns basic information about an app. 34 | 35 | Docs: https://help.crypt.bot/crypto-pay-api#getMe""" 36 | 37 | url = f'{self.__base_url}/getMe/' 38 | 39 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 40 | 41 | return MeInfo(**response['result']) 42 | 43 | async def create_invoice(self, amount: Union[int, float], currency_type: Optional[str] = None, 44 | asset: Optional[str] = None, fiat: Optional[str] = None, 45 | accepted_assets: Optional[list] = None, description: Optional[str] = None, 46 | hidden_message: Optional[str] = None, paid_btn_name: Optional[str] = None, 47 | paid_btn_url: Optional[str] = None, payload: Optional[str] = None, 48 | allow_comments: Optional[bool] = True, allow_anonymous: Optional[bool] = True, 49 | expires_in: Optional[int] = 3600) -> Invoice: 50 | """Use this method to create a new invoice. 51 | 52 | Docs: https://help.crypt.bot/crypto-pay-api#createInvoice 53 | 54 | :param amount: Amount of the invoice in float. For example: 125.50 55 | :param currency_type: Optional. Type of the price, can be “crypto” or “fiat”. Defaults to crypto. 56 | :param asset: Optional. Required if currency_type is “crypto”. Cryptocurrency alphabetic code. Supported assets: “USDT”, “TON”, “BTC”, “ETH”, “LTC”, “BNB”, “TRX” and “USDC”. 57 | :param fiat: Optional. Required if currency_type is “fiat”. Fiat currency code. Supported fiat currencies: “USD”, “EUR”, “RUB”, “BYN”, “UAH”, “GBP”, “CNY”, “KZT”, “UZS”, “GEL”, “TRY”, “AMD”, “THB”, “INR”, “BRL”, “IDR”, “AZN”, “AED”, “PLN” and “ILS". 58 | :param accepted_assets: Optional. List of cryptocurrency alphabetic codes separated comma. Assets which can be used to pay the invoice. Available only if currency_type is “fiat”. Supported assets: “USDT”, “TON”, “BTC”, “ETH”, “LTC”, “BNB”, “TRX” and “USDC” (and “JET” for testnet). Defaults to all currencies. 59 | :param description: Optional. Description for the invoice. User will see this description when they pay the invoice. Up to 1024 characters. 60 | :param hidden_message: Optional. Text of the message which will be presented to a user after the invoice is paid. Up to 2048 characters. 61 | :param paid_btn_name: Optional. Label of the button which will be presented to a user after the invoice is paid. Supported names: 62 | viewItem – “View Item” 63 | openChannel – “View Channel” 64 | openBot – “Open Bot” 65 | callback – “Return” 66 | :param paid_btn_url: Optional. Required if paid_btn_name is specified. URL opened using the button which will be presented to a user after the invoice is paid. You can set any callback link (for example, a success link or link to homepage). Starts with https or http. 67 | :param payload: Optional. Any data you want to attach to the invoice (for example, user ID, payment ID, ect). Up to 4kb. 68 | :param allow_comments: Optional. Allow a user to add a comment to the payment. Defaults to True. 69 | :param allow_anonymous: Optional. Allow a user to pay the invoice anonymously. Defaults to True. 70 | :param expires_in: Optional. You can set a payment time limit for the invoice in seconds. Values between 1-2678400 are accepted. Defaults to 3600 71 | """ 72 | 73 | if allow_comments is True: 74 | allow_comments = "true" 75 | else: 76 | allow_comments = "false" 77 | 78 | if allow_anonymous is True: 79 | allow_anonymous = "true" 80 | else: 81 | allow_anonymous = "false" 82 | 83 | url = f'{self.__base_url}/createInvoice/' 84 | 85 | if accepted_assets and type(accepted_assets) == list: 86 | accepted_assets = ",".join(map(str, accepted_assets)) 87 | 88 | params = { 89 | "asset": asset, 90 | "amount": amount, 91 | "description": description, 92 | "hidden_message": hidden_message, 93 | "paid_btn_name": paid_btn_name, 94 | "paid_btn_url": paid_btn_url, 95 | "payload": payload, 96 | "allow_comments": allow_comments, 97 | "allow_anonymous": allow_anonymous, 98 | "expires_in": expires_in, 99 | "fiat": fiat, 100 | "currency_type": currency_type, 101 | "accepted_assets": accepted_assets, 102 | } 103 | 104 | self._delete_empty_fields(params) 105 | 106 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, 107 | params=params) 108 | 109 | return Invoice(**response['result']) 110 | 111 | async def delete_invoice(self, invoice_id: int) -> bool: 112 | """Use this method to delete invoices created by your app. Returns True on success. 113 | 114 | Docs: https://help.crypt.bot/crypto-pay-api#deleteInvoice 115 | 116 | :param invoice_id: Invoice ID""" 117 | 118 | url = f'{self.__base_url}/deleteInvoice/' 119 | params = { 120 | "invoice_id": invoice_id, 121 | } 122 | 123 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, 124 | params=params) 125 | 126 | return bool(response['result']) 127 | 128 | async def create_check(self, amount: Union[float, int], asset: str) -> Check: 129 | """Use this method to create a new check. 130 | 131 | Docs: https://help.crypt.bot/crypto-pay-api#createCheck 132 | 133 | :param amount: Amount of the invoice in float. For example: 125.50 134 | :param asset: Cryptocurrency alphabetic code. Supported assets: “USDT”, “TON”, “BTC”, “ETH”, “LTC”, “BNB”, “TRX” and “USDC” (and “JET” for testnet). 135 | """ 136 | 137 | 138 | url = f'{self.__base_url}/createCheck/' 139 | 140 | params = { 141 | "amount": amount, 142 | "asset": asset, 143 | } 144 | 145 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, 146 | params=params) 147 | 148 | return Check(**response['result']) 149 | 150 | async def delete_check(self, check_id: int) -> bool: 151 | """Use this method to delete checks created by your app. Returns True on success. 152 | 153 | Docs: https://help.crypt.bot/crypto-pay-api#deleteCheck 154 | 155 | :param check_id: Check ID""" 156 | 157 | url = f'{self.__base_url}/deleteCheck/' 158 | 159 | params = { 160 | "check_id": check_id, 161 | } 162 | 163 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, 164 | params=params) 165 | 166 | return bool(response['result']) 167 | 168 | async def transfer(self, user_id: int, asset: str, amount: Union[float, int], spend_id: str, 169 | comment: Optional[str] = None, disable_send_notification: Optional[bool] = False) -> Transfer: 170 | """Use this method to send coins from your app's balance to a user. This method must first be enabled in the security settings of your app. Open @CryptoBot (@CryptoTestnetBot for testnet), go to CryptoPay → MyApps, choose an app, then go to Security -> Transfers... and tap Enable. 171 | 172 | Docs: https://help.crypt.bot/crypto-pay-api#transfer 173 | 174 | :param user_id: User ID in Telegram. User must have previously used @CryptoBot (@CryptoTestnetBot for testnet). 175 | :param asset: Cryptocurrency alphabetic code. Supported assets: “USDT”, “TON”, “BTC”, “ETH”, “LTC”, “BNB”, “TRX” and “USDC” (and “JET” for testnet). 176 | :parameter amount: Amount of the transfer in float. The minimum and maximum amount limits for each of the supported assets roughly correspond to 1-25000 USD. Use get_exchange_rates() to convert amounts. For example: 125.50 177 | :param spend_id: Random UTF-8 string unique per transfer for idempotent requests. The same spend_id can be accepted only once from your app. Up to 64 symbols. 178 | :param comment: Optional. Comment for the transfer. Users will see this comment in the notification about the transfer. Up to 1024 symbols. 179 | :param disable_send_notification: Optional. Pass true to not send to the user the notification about the transfer. Defaults to false. 180 | """ 181 | 182 | url = f'{self.__base_url}/transfer/' 183 | 184 | params = { 185 | "user_id": user_id, 186 | "asset": asset, 187 | "amount": amount, 188 | "spend_id": spend_id, 189 | "comment": comment, 190 | "disable_send_notification": disable_send_notification, 191 | } 192 | 193 | self._delete_empty_fields(params) 194 | 195 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, 196 | params=params) 197 | 198 | return Transfer(**response['result']) 199 | 200 | async def get_invoices(self, asset: Optional[str] = None, fiat: Optional[str] = None, 201 | invoice_ids: Optional[list] = None, status: Optional[str] = None, 202 | offset: Optional[int] = None, count: Optional[int] = None) -> Union[Invoice, List[Invoice]]: 203 | """Use this method to get invoices created by your app. 204 | 205 | Docs: https://help.crypt.bot/crypto-pay-api#getInvoices 206 | 207 | :param asset: Optional. Cryptocurrency alphabetic code. Supported assets: “USDT”, “TON”, “BTC”, “ETH”, “LTC”, “BNB”, “TRX” and “USDC” (and “JET” for testnet). Defaults to all currencies. 208 | :param fiat: Optional. Fiat currency code. Supported fiat currencies: “USD”, “EUR”, “RUB”, “BYN”, “UAH”, “GBP”, “CNY”, “KZT”, “UZS”, “GEL”, “TRY”, “AMD”, “THB”, “INR”, “BRL”, “IDR”, “AZN”, “AED”, “PLN” and “ILS". Defaults to all currencies. 209 | :param invoice_ids: Optional. List of invoice IDs. 210 | :param status: Optional. Status of invoices to be returned. Available statuses: “active” and “paid”. Defaults to all statuses. 211 | :param offset: Optional. Offset needed to return a specific subset of invoices. Defaults to 0. 212 | :param count: Optional. Number of invoices to be returned. Values between 1-1000 are accepted. Defaults to 100. 213 | """ 214 | 215 | url = f"{self.__base_url}/getInvoices" 216 | 217 | if invoice_ids and type(invoice_ids) == list: 218 | invoice_ids = ",".join(map(str, invoice_ids)) 219 | 220 | params = { 221 | "asset": asset, 222 | "invoice_ids": invoice_ids, 223 | "fiat": fiat, 224 | "status": status, 225 | "offset": offset, 226 | "count": count, 227 | } 228 | 229 | self._delete_empty_fields(params) 230 | 231 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, 232 | params=params) 233 | 234 | if len(response["result"]["items"]) > 0: 235 | if invoice_ids and isinstance(invoice_ids, int): 236 | return Invoice(**response["result"]["items"][0]) 237 | return [Invoice(**invoice) for invoice in response["result"]["items"]] 238 | 239 | async def get_transfers(self, asset: Optional[str] = None, transfer_ids: Optional[list] = None, 240 | offset: Optional[int] = None, count: Optional[int] = None) -> Union[Transfer, List[Transfer]]: 241 | """Use this method to get transfers created by your app. 242 | 243 | Docs: https://help.crypt.bot/crypto-pay-api#getTransfers 244 | 245 | :param asset: Optional. Cryptocurrency alphabetic code. Supported assets: “USDT”, “TON”, “BTC”, “ETH”, “LTC”, “BNB”, “TRX” and “USDC” (and “JET” for testnet). Defaults to all currencies. 246 | :param transfer_ids: Optional. List of transfer IDs. 247 | :param offset: Optional. Offset needed to return a specific subset of transfers. Defaults to 0. 248 | :param count: Optional. Number of transfers to be returned. Values between 1-1000 are accepted. Defaults to 100. 249 | """ 250 | url = f"{self.__base_url}/getTransfers" 251 | 252 | if transfer_ids and type(transfer_ids) == list: 253 | transfer_ids = ",".join(map(str, transfer_ids)) 254 | 255 | params = { 256 | "asset": asset, 257 | "transfer_ids": transfer_ids, 258 | "offset": offset, 259 | "count": count, 260 | } 261 | 262 | self._delete_empty_fields(params) 263 | 264 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, 265 | params=params) 266 | 267 | if len(response["result"]["items"]) > 0: 268 | if transfer_ids and isinstance(transfer_ids, int): 269 | return Transfer(**response["result"]["items"][0]) 270 | return [Transfer(**transfer) for transfer in response["result"]["items"]] 271 | 272 | async def get_checks(self, asset: Optional[str] = None, check_ids: Optional[list] = None, 273 | status: Optional[str] = None, offset: Optional[int] = None, 274 | count: Optional[int] = None) -> Union[Check, List[Check]]: 275 | """Use this method to get checks created by your app. 276 | 277 | Docs: https://help.crypt.bot/crypto-pay-api#getChecks 278 | 279 | :param asset: Optional. Cryptocurrency alphabetic code. Supported assets: “USDT”, “TON”, “BTC”, “ETH”, “LTC”, “BNB”, “TRX” and “USDC” (and “JET” for testnet). Defaults to all currencies. 280 | :param check_ids: Optional. List of check IDs. 281 | :param status: Optional. Status of check to be returned. Available statuses: “active” and “activated”. Defaults to all statuses. 282 | :param offset: Optional. Offset needed to return a specific subset of check. Defaults to 0. 283 | :param count: Optional. Number of check to be returned. Values between 1-1000 are accepted. Defaults to 100. 284 | """ 285 | url = f"{self.__base_url}/getChecks" 286 | 287 | if check_ids and type(check_ids) == list: 288 | check_ids = ",".join(map(str, check_ids)) 289 | 290 | params = { 291 | "asset": asset, 292 | "check_ids": check_ids, 293 | "status": status, 294 | "offset": offset, 295 | "count": count, 296 | } 297 | 298 | self._delete_empty_fields(params) 299 | 300 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, 301 | params=params) 302 | 303 | if len(response["result"]["items"]) > 0: 304 | if check_ids and isinstance(check_ids, int): 305 | return Check(**response["result"]["items"][0]) 306 | return [Check(**check) for check in response["result"]["items"]] 307 | 308 | async def get_balance(self) -> List[Balance]: 309 | """Use this method to get balances of your app. 310 | 311 | Docs: https://help.crypt.bot/crypto-pay-api#getBalance""" 312 | url = f"{self.__base_url}/getBalance" 313 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 314 | 315 | return [Balance(**balance) for balance in response["result"]] 316 | 317 | async def get_exchange_rates(self) -> List[ExchangeRate]: 318 | """Use this method to get exchange rates of supported currencies. 319 | 320 | Docs: https://help.crypt.bot/crypto-pay-api#getExchangeRates""" 321 | url = f"{self.__base_url}/getExchangeRates" 322 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 323 | 324 | return [ExchangeRate(**rate) for rate in response["result"]] 325 | 326 | async def get_currencies(self) -> List[Currency]: 327 | """Use this method to get a list of supported currencies. 328 | 329 | Docs: https://help.crypt.bot/crypto-pay-api#getCurrencies""" 330 | url = f"{self.__base_url}/getCurrencies" 331 | 332 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 333 | 334 | return [Currency(**currency) for currency in response["result"]] -------------------------------------------------------------------------------- /AsyncPayments/cryptoBot/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import List, Optional 3 | 4 | 5 | class MeInfo(BaseModel): 6 | app_id: int 7 | name: str 8 | payment_processing_bot_username: str 9 | 10 | class Invoice(BaseModel): 11 | invoice_id: int 12 | hash: str 13 | currency_type: str 14 | asset: Optional[str] = None 15 | fiat: Optional[str] = None 16 | amount: str 17 | paid_asset: Optional[str] = None 18 | paid_amount: Optional[str] = None 19 | paid_fiat_rate: Optional[str] = None 20 | accepted_assets: Optional[List[str]] = None 21 | fee_asset: Optional[str] = None 22 | fee_amount: Optional[float] = None 23 | fee: Optional[str] = None 24 | bot_invoice_url: str 25 | pay_url: str 26 | description: Optional[str] = None 27 | status: str 28 | created_at: str 29 | paid_usd_rate: Optional[str] = None 30 | usd_rate: Optional[str] = None 31 | allow_comments: bool 32 | allow_anonymous: bool 33 | expiration_date: Optional[str] = None 34 | paid_at: Optional[str] = None 35 | paid_anonymously: Optional[bool] = None 36 | comment: Optional[str] = None 37 | hidden_message: Optional[str] = None 38 | payload: Optional[str] = None 39 | paid_btn_name: Optional[str] = None 40 | paid_btn_url: Optional[str] = None 41 | 42 | class Check(BaseModel): 43 | check_id: int 44 | hash: str 45 | asset: str 46 | amount: float 47 | bot_check_url: str 48 | status: str 49 | created_at: str 50 | activated_at: str 51 | 52 | class Transfer(BaseModel): 53 | transfer_id: int 54 | user_id: int 55 | asset: str 56 | amount: float 57 | status: str 58 | completed_at: str 59 | comment: Optional[str] = None 60 | 61 | class Balance(BaseModel): 62 | currency_code: str 63 | available: float 64 | onhold: float 65 | 66 | class ExchangeRate(BaseModel): 67 | is_valid: bool 68 | is_crypto: bool 69 | is_fiat: bool 70 | source: str 71 | target: str 72 | rate: float 73 | 74 | class Currency(BaseModel): 75 | is_blockchain: bool 76 | is_stablecoin: bool 77 | is_fiat: bool 78 | name: str 79 | code: str 80 | url: Optional[str] = None 81 | decimals: int 82 | -------------------------------------------------------------------------------- /AsyncPayments/cryptomus/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import AsyncCryptomus -------------------------------------------------------------------------------- /AsyncPayments/cryptomus/api.py: -------------------------------------------------------------------------------- 1 | from ..requests import RequestsClient 2 | from typing import Optional, List 3 | from .models import Balance, Balances, CreatePayment, GenerateStaticWallet, GenerateQrCode, BlockStaticWallet, RefundPaymentsOnBlockedAddress, \ 4 | PaymentInfo, ListOfServices, PaymentHistory, Payout, PayoutHistory, ListOfServicesPayout, TransferWallet, RecurringPayment, \ 5 | ListOfRecurringPayments, ExchangeRatesList, Discount 6 | import base64 7 | import json 8 | import hashlib 9 | 10 | 11 | class AsyncCryptomus(RequestsClient): 12 | API_HOST: str = "https://cryptomus.com/gateway" 13 | 14 | def __init__(self, payment_api_key: str, merchant_id: str, payout_api_key: str) -> None: 15 | """ 16 | Initialize Cryptomus API client 17 | :param payment_api_key: Your payment API key 18 | :param merchant_id: Your merchant ID 19 | :param payout_api_key: Your payout API key 20 | """ 21 | super().__init__() 22 | self.__payment_api_key = payment_api_key 23 | self.__merchant_id = merchant_id 24 | self.__payout_api_key = payout_api_key 25 | self.__headers = { 26 | "Content-Type": "application/json", 27 | "merchant": self.__merchant_id, 28 | } 29 | self.__base_url = "https://api.cryptomus.com/v1" 30 | self.__post_method = "POST" 31 | self.__get_method = "GET" 32 | self.__payment_name = "cryptomus" 33 | self.check_values() 34 | 35 | def check_values(self): 36 | if not self.__merchant_id or not self.__payment_api_key or not self.__payout_api_key: 37 | raise ValueError('No Payment API key, merchant ID or Payout API key specified') 38 | 39 | def __generate_sign(self, data: Optional[dict] = None, is_for_payouts: Optional[bool] = False) -> dict: 40 | if data: 41 | data_encoded = base64.b64encode(json.dumps(data).encode()).decode() 42 | else: 43 | data_encoded = "" 44 | 45 | if is_for_payouts: 46 | return hashlib.md5((data_encoded + self.__payout_api_key).encode()).hexdigest() 47 | return hashlib.md5((data_encoded + self.__payment_api_key).encode()).hexdigest() 48 | 49 | async def get_balance(self) -> Balances: 50 | """Get list of your balances. 51 | 52 | Docs: https://doc.cryptomus.com/ru/business/balance""" 53 | 54 | self.__headers["sign"] = self.__generate_sign() 55 | response = await self._request(self.__payment_name, self.__post_method, f'{self.__base_url}/balance', headers=self.__headers) 56 | 57 | return Balances(merchant=[Balance(**balance) for balance in response['result'][0]['balance']['merchant']], 58 | user=[Balance(**balance) for balance in response['result'][0]['balance']['user']]) 59 | 60 | async def create_payment(self, amount: str, currency: str, order_id: str, network: Optional[str] = None, url_return: Optional[str] = None, 61 | url_success: Optional[str] = None, url_callback: Optional[str] = None, is_payment_multiple: Optional[bool] = True, 62 | lifetime: Optional[int] = 3600, to_currency: Optional[str] = None, subtract: Optional[int] = 0, 63 | accuracy_payment_percent: Optional[int] = 0, additional_data: Optional[str] = None, currencies: Optional[list] = None, 64 | except_currencies: Optional[list] = None, course_source: Optional[str] = None, from_referral_code: Optional[str] = None, 65 | discount_percent: Optional[int] = None, is_refresh: Optional[bool] = False) -> CreatePayment: 66 | 67 | """Create payment. 68 | 69 | :param amount: Amount to be paid. If there are pennies in the amount, then send them with a separator '.'. Example: 10.28 70 | :param currency: Currency code. 71 | :param order_id: Order ID in your system. The parameter should be a string consisting of alphabetic characters, numbers, underscores, and dashes. It should not contain any spaces or special characters. The order_id must be unique within the merchant invoices/static wallets/recurrence payments. When we find an existing invoice with order_id, we return its details, a new invoice will not be created. 72 | :param network: Blockchain network code. 73 | :param url_return: Before paying, the user can click on the button on the payment form and return to the store page at this URL. 74 | :param url_success: After successful payment, the user can click on the button on the payment form and return to this URL. 75 | :param url_callback: Url to which webhooks with payment status will be sent. 76 | :param is_payment_multiple: Whether the user is allowed to pay the remaining amount. This is useful when the user has not paid the entire amount of the invoice for one transaction, and you want to allow him to pay up to the full amount. If you disable this feature, the invoice will finalize after receiving the first payment and you will receive funds to your balance. 77 | :param lifetime: Min: 300. Max: 43200. The lifespan of the issued invoice (in seconds). 78 | :param to_currency: The parameter is used to specify the target currency for converting the invoice amount. When creating an invoice, you provide an amount and currency, and the API will convert that amount to the equivalent value in the to_currency. For example, to create an invoice for 20 USD in bitcoin: amount: 20, currency: USD, to_currency: BTC. The API will convert 20 USD amount to its equivalent in BTC based on the current exchange rate and the user will pay in BTC. The to_currency should always be the cryptocurrency code, not a fiat currency code. 79 | :param subtract: Min: 0. Max: 100. Percentage of the payment commission charged to the client. If you have a rate of 1%, then if you create an invoice for 100 USDT with subtract = 100 (the client pays 100% commission), the client will have to pay 101 USDT. 80 | :param accuracy_payment_percent: Min: 0. Max: 5. Acceptable inaccuracy in payment. For example, if you pass the value 5, the invoice will be marked as Paid even if the client has paid only 95% of the amount. The actual payment amount will be credited to the balance. 81 | :param additional_data: Max: 255. Additional information for you (not shown to the client). 82 | :param currencies: List of allowed currencies for payment. This is useful if you want to limit the list of coins that your customers can use to pay invoices. 83 | :param except_currencies: List of excluded currencies for payment. 84 | :param course_source: Min: 4. Max: 20. The service from which the exchange rates are taken for conversion in the invoice. 85 | :param from_referral_code: The merchant who makes the request connects to a referrer by code. For example, you are an application that generates invoices via the Cryptomus API and your customers are other stores. They enter their api key and merchant id in your application, and you send requests with their credentials and passing your referral code. Thus, your clients become referrals on your Cryptomus account and you will receive income from their turnover. 86 | :param discount_percent: Min: -99. Max: 100. Positive numbers: Allows you to set a discount. To set a 5% discount for the payment, you should pass a value: 5. Negative numbers: Allows you to set custom additional commission. To set an additional commission of 10% for the payment, you should pass a value: -10. The discount percentage when creating an invoice is taken into account only if the invoice has a specific cryptocurrency. 87 | :param is_refresh: Using this parameter, you can update the lifetime and get a new address for the invoice if the lifetime has expired. To do that, you need to pass all required parameters, and the invoice with passed order_id will be refreshed. Only address, payment_status and expired_at are changed. No other fields are changed, regardless of the parameters passed. 88 | 89 | Docs: https://doc.cryptomus.com/business/payments/creating-invoice 90 | """ 91 | 92 | url = f"{self.__base_url}/payment" 93 | params = { 94 | "amount": amount, 95 | "currency": currency, 96 | "order_id": order_id, 97 | "network": network, 98 | "url_return": url_return, 99 | "url_success": url_success, 100 | "url_callback": url_callback, 101 | "is_payment_multiple": is_payment_multiple, 102 | "lifetime": lifetime, 103 | "to_currency": to_currency, 104 | "subtract": subtract, 105 | "accuracy_payment_percent": accuracy_payment_percent, 106 | "additional_data": additional_data, 107 | "currencies": currencies, 108 | "except_currencies": except_currencies, 109 | "course_source": course_source, 110 | "from_referral_code": from_referral_code, 111 | "discount_percent": discount_percent, 112 | "is_refresh": is_refresh, 113 | } 114 | self._delete_empty_fields(params) 115 | self.__headers["sign"] = self.__generate_sign(params) 116 | 117 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 118 | 119 | return CreatePayment(**response['result']) 120 | 121 | async def payment_info(self, uuid: Optional[str] = None, order_id: Optional[str] = None) -> PaymentInfo: 122 | """Payment information. 123 | 124 | :param uuid: Invoice uuid. 125 | :param order_id: Invoice order ID. 126 | 127 | Docs: https://doc.cryptomus.com/business/payments/payment-information 128 | """ 129 | url = f"{self.__base_url}/payment/info" 130 | params = { 131 | "uuid": uuid, 132 | "order_id": order_id, 133 | } 134 | self._delete_empty_fields(params) 135 | self.__headers["sign"] = self.__generate_sign(params) 136 | 137 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 138 | 139 | return PaymentInfo(**response['result']) 140 | 141 | async def generate_static_wallet(self, currency: str, network: str, order_id: str, url_callback: Optional[str] = None, 142 | from_referral_code: Optional[str] = None) -> GenerateStaticWallet: 143 | """Creating a Static wallet. 144 | 145 | :param currency: Currency code. 146 | :param network: Blockchain network code. 147 | :param order_id: Order ID in your system. The parameter should be a string consisting of alphabetic characters, numbers, underscores, and dashes. It should not contain any spaces or special characters. The order_id must be unique within the merchant invoices/static wallets/recurrence payments. When we find an existing invoice with order_id, we return its details, a new invoice will not be created. 148 | :param url_callback: URL, to which the webhook will be sent after each top-up of the wallet 149 | :param from_referral_code: The merchant who makes the request connects to a referrer by code. 150 | 151 | 152 | Docs: https://doc.cryptomus.com/business/payments/creating-static 153 | """ 154 | url = f"{self.__base_url}/wallet" 155 | params = { 156 | "currency": currency, 157 | "network": network, 158 | "order_id": order_id, 159 | "url_callback": url_callback, 160 | "from_referral_code": from_referral_code, 161 | } 162 | self._delete_empty_fields(params) 163 | self.__headers["sign"] = self.__generate_sign(params) 164 | 165 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 166 | 167 | return GenerateStaticWallet(**response['result']) 168 | 169 | async def generate_qr_code_for_wallet(self, wallet_address_uuid: str) -> GenerateQrCode: 170 | """Generate a QR-code for the static wallet address. 171 | 172 | :param wallet_address_uuid: Uuid of a static wallet. 173 | 174 | Docs: https://doc.cryptomus.com/business/payments/qr-code-pay-form 175 | """ 176 | url = f"{self.__base_url}/wallet/qr" 177 | params = { 178 | "wallet_address_uuid": wallet_address_uuid, 179 | } 180 | self.__headers["sign"] = self.__generate_sign(params) 181 | 182 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 183 | 184 | return GenerateQrCode(**response['result']) 185 | 186 | async def generate_qr_code_for_invoice(self, merchant_payment_uuid: str) -> GenerateQrCode: 187 | """Generate a QR-code for the invoice address. 188 | 189 | :param merchant_payment_uuid: Invoice uuid. 190 | 191 | Docs: https://doc.cryptomus.com/business/payments/qr-code-pay-form 192 | """ 193 | url = f"{self.__base_url}/payment/qr" 194 | params = { 195 | "merchant_payment_uuid": merchant_payment_uuid, 196 | } 197 | self.__headers["sign"] = self.__generate_sign(params) 198 | 199 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 200 | 201 | return GenerateQrCode(**response['result']) 202 | 203 | async def block_static_wallet(self, uuid: Optional[str] = None, order_id: Optional[str] = None, is_force_refund: Optional[bool] = False) -> BlockStaticWallet: 204 | """Block static wallet. 205 | 206 | :param uuid: Uuid of a static wallet. 207 | :param order_id: Order ID of a static wallet. 208 | :param is_force_refund: Refund all incoming payments to sender’s address. 209 | 210 | Docs: https://doc.cryptomus.com/business/payments/block-wallet 211 | """ 212 | url = f"{self.__base_url}/wallet/block-address" 213 | params = { 214 | "uuid": uuid, 215 | "order_id": order_id, 216 | "is_force_refund": is_force_refund, 217 | } 218 | self._delete_empty_fields(params) 219 | self.__headers["sign"] = self.__generate_sign(params) 220 | 221 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 222 | 223 | return BlockStaticWallet(**response['result']) 224 | 225 | async def refund_payments_on_blocked_address(self, address: str, uuid: Optional[str] = None, order_id: Optional[str] = None) -> RefundPaymentsOnBlockedAddress: 226 | """Refund payments on blocked address. 227 | 228 | :param address: Uuid of a static wallet. 229 | :param uuid: Order ID of a static wallet. 230 | :param order_id: Refund all blocked funds to this address. 231 | 232 | Docs: https://doc.cryptomus.com/business/payments/refundblocked 233 | """ 234 | url = f"{self.__base_url}/blocked-address-refund" 235 | params = { 236 | "address": address, 237 | "uuid": uuid, 238 | "order_id": order_id, 239 | } 240 | self._delete_empty_fields(params) 241 | self.__headers["sign"] = self.__generate_sign(params) 242 | 243 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 244 | 245 | return RefundPaymentsOnBlockedAddress(**response['result']) 246 | 247 | async def refund(self, address: str, is_subtract: bool, uuid: Optional[str] = None, order_id: Optional[str] = None) -> bool: 248 | """Refund. 249 | 250 | :param address: The address to which the refund should be made. 251 | :param is_subtract: Whether to take a commission from the merchant's balance or from the refund amount. True - take the commission from merchant balance. False - reduce the refundable amount by the commission amount. 252 | :param uuid: Invoice uuid. 253 | :param order_id: Invoice order ID. 254 | 255 | Docs: https://doc.cryptomus.com/business/payments/refund 256 | """ 257 | url = f"{self.__base_url}/payment/refund" 258 | params = { 259 | "address": address, 260 | "is_subtract": is_subtract, 261 | "uuid": uuid, 262 | "order_id": order_id, 263 | } 264 | self._delete_empty_fields(params) 265 | self.__headers["sign"] = self.__generate_sign(params) 266 | 267 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 268 | 269 | return True if response['state'] == 0 else False 270 | 271 | async def resend_webhook(self, uuid: Optional[str] = None, order_id: Optional[str] = None) -> bool: 272 | """Resend webhook. 273 | 274 | :param uuid: Invoice uuid. 275 | :param order_id: Invoice order ID. 276 | 277 | Docs: https://doc.cryptomus.com/business/payments/resend-webhook 278 | """ 279 | url = f"{self.__base_url}/payment/resend" 280 | params = { 281 | "uuid": uuid, 282 | "order_id": order_id, 283 | } 284 | self._delete_empty_fields(params) 285 | self.__headers["sign"] = self.__generate_sign(params) 286 | 287 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 288 | 289 | return True if response['state'] == 0 else False 290 | 291 | async def test_webhook_payment(self, url_callback: str, currency: str, network: str, status: str, uuid: Optional[str] = None, 292 | order_id: Optional[str] = None) -> bool: 293 | """Testing payment webhook. 294 | 295 | :param url_callback: Url to which webhooks with payment status will be sent. 296 | :param currency: Invoice currency code. 297 | :param network: Invoice network code. 298 | :param status: Payment status. 299 | :param uuid: uuid of the invoice. 300 | :param order_id: Order ID of the invoice. 301 | 302 | Docs: https://doc.cryptomus.com/business/payments/testing-webhook 303 | """ 304 | url = f"{self.__base_url}/test-webhook/payment" 305 | params = { 306 | "url_callback": url_callback, 307 | "currency": currency, 308 | "network": network, 309 | "status": status, 310 | "uuid": uuid, 311 | "order_id": order_id, 312 | } 313 | self._delete_empty_fields(params) 314 | self.__headers["sign"] = self.__generate_sign(params) 315 | 316 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 317 | 318 | return True if response['state'] == 0 else False 319 | 320 | async def test_webhook_wallet(self, url_callback: str, currency: str, network: str, status: str, uuid: Optional[str] = None, 321 | order_id: Optional[str] = None) -> bool: 322 | """Testing wallet webhook. 323 | 324 | :param url_callback: Url to which webhooks with payment status will be sent. 325 | :param currency: Invoice currency code. 326 | :param network: Invoice network code. 327 | :param status: Payment status. 328 | :param uuid: uuid of the invoice. 329 | :param order_id: Order ID of the invoice. 330 | 331 | Docs: https://doc.cryptomus.com/business/payments/testing-webhook 332 | """ 333 | url = f"{self.__base_url}/test-webhook/wallet" 334 | params = { 335 | "url_callback": url_callback, 336 | "currency": currency, 337 | "network": network, 338 | "status": status, 339 | "uuid": uuid, 340 | "order_id": order_id, 341 | } 342 | self._delete_empty_fields(params) 343 | self.__headers["sign"] = self.__generate_sign(params) 344 | 345 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 346 | 347 | return True if response['state'] == 0 else False 348 | 349 | async def test_webhook_payout(self, url_callback: str, currency: str, network: str, status: str, uuid: Optional[str] = None, 350 | order_id: Optional[str] = None) -> bool: 351 | """Testing payout webhook. 352 | 353 | :param url_callback: Url to which webhooks with payment status will be sent. 354 | :param currency: Payout currency code. 355 | :param network: Payout network code. 356 | :param status: Payout status. 357 | :param uuid: uuid of the Payout. 358 | :param order_id: Order ID of the Payout. 359 | 360 | Docs: https://doc.cryptomus.com/business/payments/testing-webhook 361 | """ 362 | url = f"{self.__base_url}/test-webhook/payout" 363 | params = { 364 | "url_callback": url_callback, 365 | "currency": currency, 366 | "network": network, 367 | "status": status, 368 | "uuid": uuid, 369 | "order_id": order_id, 370 | } 371 | self._delete_empty_fields(params) 372 | self.__headers["sign"] = self.__generate_sign(params) 373 | 374 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 375 | 376 | return True if response['state'] == 0 else False 377 | 378 | async def list_of_services(self) -> List[ListOfServices]: 379 | """List of services. 380 | 381 | Docs: https://doc.cryptomus.com/business/payments/list-of-services 382 | """ 383 | url = f"{self.__base_url}/payment/services" 384 | self.__headers["sign"] = self.__generate_sign() 385 | 386 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 387 | 388 | return [ListOfServices(**service) for service in response["result"]] 389 | 390 | async def payment_history(self, date_from: Optional[str] = None, date_to: Optional[str] = None, cursor: Optional[str] = None) -> PaymentHistory: 391 | """Payment history. 392 | 393 | :param date_from: Filtering by creation date, from. Format: YYYY-MM-DD H:mm:ss 394 | :param date_to: Filtering by creation date, to. Format: YYYY-MM-DD H:mm:ss 395 | :param cursor: Cursor to page. 396 | 397 | Docs: https://doc.cryptomus.com/business/payments/payment-history 398 | """ 399 | url = f"{self.__base_url}/payment/list" 400 | if cursor: 401 | url += f"?cursor={cursor}" 402 | params = { 403 | "date_from": date_from, 404 | "date_to": date_to, 405 | } 406 | self._delete_empty_fields(params) 407 | self.__headers["sign"] = self.__generate_sign(params) 408 | 409 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 410 | 411 | return PaymentHistory(**response['result']) 412 | 413 | async def create_payout(self, amount: str, currency: str, order_id: str, address: str, is_subtract: bool, network: str, 414 | url_callback: Optional[str] = None, to_currency: Optional[str] = None, 415 | course_source: Optional[str] = None, from_currency: Optional[str] = None, 416 | priority: Optional[str] = None, memo: Optional[str] = None) -> Payout: 417 | """Creating a payout. 418 | 419 | :param amount: Payout amount. 420 | :param currency: Currency code for the payout. If Currency is fiat, the to_currency parameter is required. 421 | :param order_id: Order ID in your system. The parameter should be a string consisting of alphabetic characters, numbers, underscores, and dashes. It should not contain any spaces or special characters. The order_id must be unique within the merchant payouts. When we find an existing payout with order_id, we return its details, a new payout will not be created. 422 | :param address: The address of the wallet to which the withdrawal will be made. 423 | :param is_subtract: Defines where the withdrawal fee will be deducted. True - from your balance. False - from payout amount, the payout amount will be decreased. 424 | :param network: Blockchain network code. Not required when the currency/to_currency parameters is a cryptocurrency and has only one network, for example BTC. 425 | :param url_callback: URL to which webhooks with payout status will be sent. 426 | :param to_currency: Cryptocurrency code in which the payout will be made. It is used when the currency parameter is fiat. 427 | :param course_source: The service from which the exchange rates are taken for conversion in the invoice. The parameter is applied only if the currency is fiat, otherwise the default value is taken from the merchant's settings. Available values: Binance, BinanceP2p, Exmo, Kucoin, Garantexio. 428 | :param from_currency: Allows to automatically convert the withdrawal amount and use the from_currency balance. Only USDT is available. 429 | :param priority: The parameter for selecting the withdrawal priority. The cost of the withdrawal fee depends on the selected parameter. This parameter is applied only in case of using the BTC, ETH, POLYGON, and BSC networks. Available values: recommended, economy, high, highest. 430 | :param memo: Additional identifier for TON, used to specify a particular recipient or target. 431 | 432 | Docs: https://doc.cryptomus.com/business/payouts/creating-payout 433 | """ 434 | url = f"{self.__base_url}/payout" 435 | params = { 436 | "amount": amount, 437 | "currency": currency, 438 | "order_id": order_id, 439 | "address": address, 440 | "is_subtract": is_subtract, 441 | "network": network, 442 | "url_callback": url_callback, 443 | "to_currency": to_currency, 444 | "course_source": course_source, 445 | "from_currency": from_currency, 446 | "priority": priority, 447 | "memo": memo, 448 | } 449 | self._delete_empty_fields(params) 450 | self.__headers["sign"] = self.__generate_sign(params, True) 451 | 452 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 453 | 454 | return Payout(**response['result']) 455 | 456 | async def payout_info(self, uuid: Optional[str] = None, order_id: Optional[str] = None) -> Payout: 457 | """Payout information. 458 | 459 | :param uuid: Payout uuid. 460 | :param order_id: Payout order ID. 461 | 462 | Docs: https://doc.cryptomus.com/business/payouts/payout-information 463 | """ 464 | url = f"{self.__base_url}/payout/info" 465 | params = { 466 | "uuid": uuid, 467 | "order_id": order_id, 468 | } 469 | self._delete_empty_fields(params) 470 | self.__headers["sign"] = self.__generate_sign(params, True) 471 | 472 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 473 | 474 | return Payout(**response['result']) 475 | 476 | async def payout_history(self, date_from: Optional[str] = None, date_to: Optional[str] = None, cursor: Optional[str] = None) -> PayoutHistory: 477 | """Payout history. 478 | 479 | :param date_from: Filtering by creation date, from. Format: YYYY-MM-DD H:mm:ss. 480 | :param date_to: Filtering by creation date, to. Format: YYYY-MM-DD H:mm:ss. 481 | :param cursor: Cursor to page. 482 | 483 | Docs: https://doc.cryptomus.com/business/payouts/payout-history 484 | """ 485 | url = f"{self.__base_url}/payout/list" 486 | if cursor: 487 | url += f"?cursor={cursor}" 488 | params = { 489 | "date_from": date_from, 490 | "date_to": date_to, 491 | } 492 | self._delete_empty_fields(params) 493 | self.__headers["sign"] = self.__generate_sign(params, True) 494 | 495 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 496 | 497 | return PayoutHistory(**response['result']) 498 | 499 | async def list_of_services_payout(self) -> List[ListOfServicesPayout]: 500 | """List of services. 501 | 502 | Docs: https://doc.cryptomus.com/business/payouts/list-of-services 503 | """ 504 | url = f"{self.__base_url}/payout/services" 505 | self.__headers["sign"] = self.__generate_sign(dict(), True) 506 | 507 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 508 | 509 | return [ListOfServicesPayout(**service) for service in response["result"]] 510 | 511 | async def transfer_to_personal_wallet(self, amount: str, currency: str) -> TransferWallet: 512 | """Transfer to personal wallet. 513 | 514 | :param amount: Amount to transfer. 515 | :param currency: Currency code. Only cryptocurrency code is allowed.. 516 | 517 | Docs: https://doc.cryptomus.com/business/payouts/transfer-to-personal 518 | """ 519 | url = f"{self.__base_url}/transfer/to-personal" 520 | params = { 521 | "amount": amount, 522 | "currency": currency, 523 | } 524 | self.__headers["sign"] = self.__generate_sign(params, True) 525 | 526 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 527 | 528 | return TransferWallet(**response['result']) 529 | 530 | 531 | 532 | async def transfer_to_business_wallet(self, amount: str, currency: str) -> TransferWallet: 533 | """Transfer to business wallet. 534 | 535 | :param amount: Amount to transfer. 536 | :param currency: Currency code. Only cryptocurrency code is allowed.. 537 | 538 | Docs: https://doc.cryptomus.com/business/payouts/transfer-to-personal 539 | """ 540 | url = f"{self.__base_url}/transfer/to-business" 541 | params = { 542 | "amount": amount, 543 | "currency": currency, 544 | } 545 | self.__headers["sign"] = self.__generate_sign(params, True) 546 | 547 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 548 | 549 | return TransferWallet(**response['result']) 550 | 551 | async def creating_recurring_payment(self, amount: str, currency: str, name: str, period: str, to_currency: Optional[str] = None, 552 | order_id: Optional[str] = None, url_callback: Optional[str] = None, discount_days: Optional[str] = None, 553 | discount_amount: Optional[str] = None, additional_data: Optional[str] = None) -> RecurringPayment: 554 | """Creating recurring payment. 555 | 556 | :param amount: Recurring payment amount. 557 | :param currency: Currency code. 558 | :param name: Recurring payment name. 559 | :param period: Recurring payment period. Available: weekly, monthly, three_month. 560 | :param to_currency: Currency code for accepting payments. The parameter is used to specify the target currency for converting the recurrent payment amount. For example, to create an recurrent payment for 20 USD in bitcoin: amount: 20, currency: USD, to_currency: BTC. The API will convert 20 USD amount to its equivalent in BTC based on the current exchange rate and the user will pay in BTC. The to_currency should always be the cryptocurrency code, not a fiat currency code. 561 | :param order_id: Order ID in your system. 562 | :param url_callback: Url to which webhooks with payment status will be sent. 563 | :param discount_days: Discount period days (required with 'discount_amount'). 564 | :param discount_amount: Discount amount (required with 'discount_days').Here the amount in the currency of the parameter ‘currency’. 565 | :param additional_data: Additional recurring payment details. 566 | 567 | Docs: https://doc.cryptomus.com/business/recurring/creating 568 | """ 569 | url = f"{self.__base_url}/recurrence/create" 570 | params = { 571 | "amount": amount, 572 | "currency": currency, 573 | "name": name, 574 | "period": period, 575 | "to_currency": to_currency, 576 | "order_id": order_id, 577 | "url_callback": url_callback, 578 | "discount_days": discount_days, 579 | "discount_amount": discount_amount, 580 | "additional_data": additional_data, 581 | } 582 | self._delete_empty_fields(params) 583 | self.__headers["sign"] = self.__generate_sign(params) 584 | 585 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 586 | 587 | return RecurringPayment(**response['result']) 588 | 589 | async def recurring_payment_info(self, uuid: Optional[str] = None, order_id: Optional[str] = None) -> RecurringPayment: 590 | """Payment information. 591 | 592 | :param uuid: Recurrence uuid. 593 | :param order_id: Recurrence order ID. 594 | 595 | Docs: https://doc.cryptomus.com/business/recurring/info""" 596 | url = f"{self.__base_url}/recurrence/info" 597 | params = { 598 | "uuid": uuid, 599 | "order_id": order_id, 600 | } 601 | self._delete_empty_fields(params) 602 | self.__headers["sign"] = self.__generate_sign(params) 603 | 604 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 605 | 606 | return RecurringPayment(**response['result']) 607 | 608 | async def list_of_recurring_payments(self, cursor: Optional[str] = None) -> ListOfRecurringPayments: 609 | """List of recurring payments. 610 | 611 | Docs: https://doc.cryptomus.com/business/recurring/list 612 | """ 613 | url = f"{self.__base_url}/recurrence/list" 614 | if cursor: 615 | url += f"?cursor={cursor}" 616 | self.__headers["sign"] = self.__generate_sign() 617 | 618 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 619 | 620 | return ListOfRecurringPayments(**response['result']) 621 | 622 | async def cancel_recurring_payment(self, uuid: Optional[str] = None, order_id: Optional[str] = None) -> RecurringPayment: 623 | """Cancel recurring payment 624 | 625 | :param uuid: Recurrence uuid. 626 | :param order_id: Order ID in your system. 627 | 628 | Docs: https://doc.cryptomus.com/business/recurring/cancel 629 | """ 630 | url = f"{self.__base_url}/recurrence/cancel" 631 | params = { 632 | "uuid": uuid, 633 | "order_id": order_id, 634 | } 635 | self.__headers["sign"] = self.__generate_sign(params) 636 | 637 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 638 | 639 | return RecurringPayment(**response['result']) 640 | 641 | async def exchange_rates_list(self, currency: str) -> List[ExchangeRatesList]: 642 | """Exchange rates list. 643 | 644 | Docs: https://doc.cryptomus.com/business/exchange-rates/list 645 | """ 646 | url = f"{self.__base_url}/exchange-rate/{currency}/list" 647 | self.__headers["sign"] = self.__generate_sign() 648 | 649 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 650 | 651 | return [ExchangeRatesList(**rate) for rate in response["result"]] 652 | 653 | async def list_of_discounts(self) -> List[Discount]: 654 | """List of discounts. 655 | 656 | Docs: https://doc.cryptomus.com/business/discount/list 657 | """ 658 | url = f"{self.__base_url}/payment/discount/list" 659 | self.__headers["sign"] = self.__generate_sign() 660 | 661 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 662 | 663 | return [Discount(**discount) for discount in response["result"]] 664 | 665 | async def set_discount_to_payment_method(self, currency: str, network: str, discount_percent: int) -> Discount: 666 | """Set discount to payment method. 667 | 668 | :param currency: Currency code. 669 | :param network: Blockchain network code. 670 | :param discount_percent: Discount percent. 671 | 672 | Docs: https://doc.cryptomus.com/business/discount/set 673 | """ 674 | url = f"{self.__base_url}/payment/discount/set" 675 | params = { 676 | "currency": currency, 677 | "network": network, 678 | "discount_percent": discount_percent, 679 | } 680 | self.__headers["sign"] = self.__generate_sign(params) 681 | 682 | response = await self._request(self.__payment_name, self.__post_method, url, json=params, headers=self.__headers) 683 | 684 | return Discount(**response["result"]) -------------------------------------------------------------------------------- /AsyncPayments/cryptomus/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | from typing import Optional, Union, List 3 | 4 | 5 | class Balances(BaseModel): 6 | merchant: list 7 | user: list 8 | 9 | 10 | class Balance(BaseModel): 11 | uuid: str 12 | balance: str 13 | currency_code: str 14 | balance_usd: str 15 | 16 | 17 | class CreatePayment(BaseModel): 18 | uuid: str 19 | order_id: str 20 | amount: str 21 | payment_amount: Optional[Union[str, int]] = None 22 | payment_amount_usd: Optional[Union[str, int]] = None 23 | payer_amount: Optional[Union[str, int]] = None 24 | payer_amount_exchange_rate: Optional[Union[str, int]] = None 25 | discount_percent: Optional[Union[str, int]] = None 26 | discount: str 27 | payer_currency: Optional[Union[str, int]] = None 28 | currency: str 29 | comments: Optional[Union[str, dict, list]] = None 30 | merchant_amount: Optional[Union[str, int]] = None 31 | network: Optional[str] = None 32 | address: Optional[str] = None 33 | from_: Optional[str] = Field(alias="from", default=None) 34 | txid: Optional[str] = None 35 | payment_status: str 36 | url: str 37 | expired_at: int 38 | status: str 39 | is_final: bool 40 | aditional_data: Optional[str] = None 41 | created_at: str 42 | updated_at: str 43 | commission: Optional[Union[str, int]] = None 44 | address_qr_code: Optional[str] = None 45 | mercuryo_payment_link: Optional[str] = None 46 | 47 | 48 | class GenerateStaticWallet(BaseModel): 49 | wallet_uuid: str 50 | uuid: str 51 | address: str 52 | network: str 53 | currency: str 54 | url: str 55 | 56 | 57 | class GenerateQrCode(BaseModel): 58 | image: str 59 | 60 | 61 | class BlockStaticWallet(BaseModel): 62 | uuid: str 63 | status: str 64 | 65 | 66 | class RefundPaymentsOnBlockedAddress(BaseModel): 67 | commission: str 68 | amount: str 69 | 70 | 71 | class PaymentInfo(BaseModel): 72 | uuid: str 73 | order_id: str 74 | amount: str 75 | payment_amount: Optional[str] = None 76 | payer_amount: Optional[str] = None 77 | discount_percent: Optional[Union[int, float, str]] = None 78 | discount: str 79 | payer_currency: Optional[str] = None 80 | currency: str 81 | merchant_amount: Optional[str] = None 82 | network: Optional[str] = None 83 | address: Optional[str] = None 84 | from_: Optional[str] = Field(alias="from", default=None) 85 | txid: Optional[str] = None 86 | payment_status: str 87 | url: str 88 | expired_at: int 89 | status: str 90 | is_final: bool 91 | additional_data: Optional[str] = None 92 | created_at: str 93 | updated_at: str 94 | 95 | 96 | class ServiceInfo: 97 | class ServiceLimit(BaseModel): 98 | min_amount: str 99 | max_amount: str 100 | 101 | 102 | class ServiceCommission(BaseModel): 103 | fee_amount: str 104 | percent: str 105 | 106 | 107 | class ListOfServices(BaseModel): 108 | network: str 109 | currency: str 110 | is_available: bool 111 | limit: ServiceInfo.ServiceLimit 112 | commission: ServiceInfo.ServiceCommission 113 | 114 | 115 | class HistoryPaginate(BaseModel): 116 | count: int 117 | hasPages: bool 118 | nextCursor: Optional[str] = None 119 | previousCursor: Optional[str] = None 120 | perPage: int 121 | 122 | 123 | class PaymentHistory(BaseModel): 124 | items: List[PaymentInfo] 125 | paginate: HistoryPaginate 126 | 127 | 128 | class PayoutHistoryItem(BaseModel): 129 | uuid: str 130 | amount: str 131 | currency: str 132 | network: str 133 | address: str 134 | txid: Optional[str] = None 135 | status: str 136 | is_final: bool 137 | balance: Union[str, int] 138 | created_at: str 139 | updated_at: str 140 | 141 | 142 | class PayoutHistory(BaseModel): 143 | merchant_uuid: Optional[str] = None 144 | items: List[PayoutHistoryItem] 145 | paginate: HistoryPaginate 146 | 147 | 148 | class Payout(BaseModel): 149 | uuid: str 150 | amount: str 151 | currency: str 152 | network: str 153 | address: str 154 | txid: Optional[str] = None 155 | status: str 156 | is_final: bool 157 | balance: Union[str, int] 158 | payer_currency: str 159 | payer_amount: Union[str, int] 160 | 161 | 162 | class ListOfServicesPayout(BaseModel): 163 | network: str 164 | currency: str 165 | is_available: bool 166 | limit: ServiceInfo.ServiceLimit 167 | commission: ServiceInfo.ServiceCommission 168 | 169 | 170 | class TransferWallet(BaseModel): 171 | user_wallet_transaction_uuid: str 172 | user_wallet_balance: str 173 | merchant_transaction_uuid: str 174 | merchant_balance: str 175 | 176 | 177 | class RecurringPayment(BaseModel): 178 | uuid: str 179 | name: str 180 | order_id: Optional[str] = None 181 | amount: str 182 | currency: str 183 | payer_currency: str 184 | payer_amount_usd: str 185 | payer_amount: str 186 | url_callback: Optional[str] = None 187 | period: str 188 | status: str 189 | url: str 190 | last_pay_off: Optional[str] = None 191 | additional_data: Optional[str] = None 192 | 193 | 194 | class ListOfRecurringPayments(BaseModel): 195 | merchant_uuid: Optional[str] = None 196 | items: List[RecurringPayment] 197 | paginate: HistoryPaginate 198 | 199 | 200 | class ExchangeRatesList(BaseModel): 201 | from_: Optional[str] = Field(alias="from", default=None) 202 | to: str 203 | course: str 204 | 205 | 206 | class Discount(BaseModel): 207 | currency: str 208 | network: str 209 | discount: Union[str, int, float] 210 | 211 | 212 | class CurrenciesNames: 213 | USDC: str = "USDC" 214 | ETH: str = "ETH" 215 | USDT: str = "USDT" 216 | AVAX: str = "AVAX" 217 | BCH: str = "BCH" 218 | BNB: str = "BNB" 219 | CGPT: str = "CGPT" 220 | DAI: str = "DAI" 221 | BTC: str = "BTC" 222 | DASH: str = "DASH" 223 | DOGE: str = "DOGE" 224 | SHIB: str = "SHIB" 225 | MATIC: str = "MATIC" 226 | VERSE: str = "VERSE" 227 | LTC: str = "LTC" 228 | CRMS: str = "CRMS" 229 | SOL: str = "SOL" 230 | TON: str = "TON" 231 | HMSTR: str = "HMSTR" 232 | TRX: str = "TRX" 233 | XMR: str = "XMR" 234 | 235 | 236 | class NetworkNames: 237 | ARBITRUM: str = "ARBITRUM" 238 | AVALANCHE: str = "AVALANCHE" 239 | BCH: str = "BCH" 240 | BSC: str = "BSC" 241 | BTC: str = "BTC" 242 | DASH: str = "DASH" 243 | DOGE: str = "DOGE" 244 | ETH: str = "ETH" 245 | LTC: str = "LTC" 246 | POLYGON: str = "POLYGON" 247 | SOL: str = "SOL" 248 | TON: str = "TON" 249 | TRON: str = "TRON" 250 | XMR: str = "XMR" 251 | 252 | 253 | class InvoiceStatuses: 254 | PROCESS: str = "process" 255 | CHECK: str = "check" 256 | CONFIRM_CHECK: str = "confirm_check" 257 | PAID: str = "paid" 258 | PAID_OVER: str = "paid_over" 259 | FAIL: str = "fail" 260 | WRONG_AMOUNT: str = "wrong_amount" 261 | WRONG_AMOUNT_WAITING = "wrong_amount_waiting" 262 | CANCEL: str = "cancel" 263 | SYSTEM_FAIL: str = "system_fail" 264 | REFUND_PROCESS: str = "refund_process" 265 | REFUND_FAIL: str = "refund_fail" 266 | REFUND_PAID: str = "refund_paid" 267 | LOCKED: str = "locked" 268 | 269 | 270 | class PayoutStatuses: 271 | PROCESS: str = "process" 272 | CHECK: str = "check" 273 | PAID: str = "paid" 274 | FAIL: str = "fail" 275 | CANCEL: str = "cancel" 276 | SYSTEM_FAIL: str = "system_fail" -------------------------------------------------------------------------------- /AsyncPayments/crystalPay/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import AsyncCrystalPay -------------------------------------------------------------------------------- /AsyncPayments/crystalPay/api.py: -------------------------------------------------------------------------------- 1 | from ..requests import RequestsClient 2 | from typing import Optional, Union, List 3 | from .models import CreatePayment, CassaInfo, PayoffCreate, TickersRate, PayoffRequest, \ 4 | PaymentInfo, BalancesList, Balance, Methods, Method, SwapPair, \ 5 | CreateSwap, SwapInfo, CreateTransfer, TransferInfo, Stats 6 | import json 7 | import hashlib 8 | 9 | 10 | class AsyncCrystalPay(RequestsClient): 11 | API_HOST: str = "https://crystalpay.io" 12 | 13 | def __init__(self, login: str, secret: str, salt: str) -> None: 14 | """ 15 | Initialize CrystalPay API client 16 | :param login: Your Login 17 | :param secret: Your Secret 18 | :param salt: Your Salt 19 | """ 20 | super().__init__() 21 | self.__login = login 22 | self.__secret = secret 23 | self.__salt = salt 24 | self.__headers = { 25 | 'Content-Type': 'application/json', 26 | } 27 | self.__base_url = "https://api.crystalpay.io/v3" 28 | self.__post_method = "POST" 29 | self.__payment_name = "crystalPay" 30 | self.check_values() 31 | 32 | def check_values(self): 33 | if not self.__login or not self.__secret or not self.__salt: 34 | raise ValueError('No Secret, Login or Salt specified') 35 | 36 | async def get_cassa_info(self, hide_empty: Optional[bool]= False) -> CassaInfo: 37 | """Get cash info. 38 | 39 | Docs: https://docs.crystalpay.io/metody-api/me-kassa/poluchenie-informacii-o-kasse""" 40 | 41 | url = f'{self.__base_url}/me/info/' 42 | 43 | params = { 44 | "auth_login": self.__login, 45 | "auth_secret": self.__secret, 46 | "hide_empty": hide_empty, 47 | } 48 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 49 | 50 | return CassaInfo(**response) 51 | 52 | async def get_balance_list(self, hide_empty: Optional[bool] = False) -> BalancesList: 53 | """Get balances list. 54 | 55 | Docs: https://docs.crystalpay.io/metody-api/balance-balansy/poluchenie-spiska-balansov 56 | 57 | :param hide_empty: Optional. Hide empty balances. Defaults to False""" 58 | 59 | url = f'{self.__base_url}/balance/list/' 60 | 61 | params = { 62 | "auth_login": self.__login, 63 | "auth_secret": self.__secret, 64 | "hide_empty": hide_empty, 65 | } 66 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 67 | if response['items']: 68 | return BalancesList(**response['items']) 69 | else: 70 | return [] 71 | 72 | async def get_balance(self, method: str) -> Balance: 73 | """Get balance of the method. 74 | 75 | Docs: https://docs.crystalpay.io/metody-api/balance-balansy/poluchenie-balansa 76 | 77 | :param method: Internal name of the account/method.""" 78 | 79 | url = f'{self.__base_url}/balance/get/' 80 | 81 | params = { 82 | "auth_login": self.__login, 83 | "auth_secret": self.__secret, 84 | "method": method, 85 | } 86 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 87 | return Balance(**response) 88 | 89 | async def get_payment_methods(self, compact: Optional[bool] = False) -> Methods: 90 | """Get list of a methods. 91 | 92 | Docs: https://docs.crystalpay.io/metody-api/method-metody/poluchenie-spiska-metodov 93 | 94 | :param compact: Displaying only basic information.""" 95 | 96 | url = f'{self.__base_url}/method/list/' 97 | 98 | params = { 99 | "auth_login": self.__login, 100 | "auth_secret": self.__secret, 101 | "compact": compact, 102 | } 103 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 104 | 105 | return Methods(**response['items']) 106 | 107 | 108 | async def get_payment_method(self, method: str) -> Method: 109 | """Get info about a method. 110 | 111 | Docs: https://docs.crystalpay.io/metody-api/method-metody/poluchenie-metoda 112 | 113 | :param compact: The internal name of the method.""" 114 | 115 | url = f'{self.__base_url}/method/get/' 116 | 117 | params = { 118 | "auth_login": self.__login, 119 | "auth_secret": self.__secret, 120 | "method": method, 121 | } 122 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 123 | 124 | return Method(**response) 125 | 126 | 127 | async def edit_payment_method(self, method: str, extra_commission_percent: Union[int, float], enabled: bool) -> bool: 128 | """Edit payment method 129 | 130 | Dosc: https://docs.crystalpay.io/api/metody-oplaty/izmenenie-nastroek-metoda-oplaty 131 | 132 | :param method: Payment method, for example: LZTMARKET, BITCOIN 133 | :param extra_commission_percent: Additional cash desk commission for payment method, in percent 134 | :param enabled: Enable/Disable payment method 135 | 136 | :return: True if successful, else exception BadRequest 137 | """ 138 | 139 | url = f'{self.__base_url}/method/edit/' 140 | 141 | params = { 142 | "auth_login": self.__login, 143 | "auth_secret": self.__secret, 144 | "method": method, 145 | "extra_commission_percent": extra_commission_percent, 146 | "enabled": enabled, 147 | } 148 | 149 | await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 150 | 151 | return True 152 | 153 | async def create_payment( 154 | self, amount: Union[int, float], amount_currency: Optional[str] = "RUB", required_methods: Optional[str] = None, 155 | _type: Optional[str] = "purchase", description: Optional[str] = None, redirect_url: Optional[str] = None, 156 | callback_url: Optional[str] = None, extra: Optional[str] = None, payer_details: Optional[str] = None, 157 | lifetime: Optional[int] = 60) -> CreatePayment: 158 | """Generate payment url. 159 | 160 | Docs: https://docs.crystalpay.io/metody-api/invoice-platezhi/sozdanie-invoisa 161 | 162 | :param amount: Order amount. 163 | :param amount_currency: Currency. Default to 'RUB', for example: USD, BTC, ETH 164 | :param required_methods: Pre-selected payment method, for example: LZTMARKET, BITCOIN 165 | :param _type: Invoice type. possible options: purchase, topup 166 | :param description: The description or purpose of the payment is displayed to the payer on the payment page, for example: Account purchase #12345678 167 | :param redirect_url: Redirect link after payment 168 | :param callback_url: Link for HTTP Callback notification after successful payment 169 | :param extra: Any internal data, for example: Payment ID in your system 170 | :param payer_details: Payer email 171 | :param lifetime: Invoice lifetime in minutes, maximum - 4320. Default to 60""" 172 | 173 | url = f'{self.__base_url}/invoice/create/' 174 | 175 | params = { 176 | "auth_login": self.__login, 177 | "auth_secret": self.__secret, 178 | "amount": amount, 179 | "amount_currency": amount_currency, 180 | "required_methods": required_methods, 181 | "type": _type, 182 | "description": description, 183 | "redirect_url": redirect_url, 184 | "callback_url": callback_url, 185 | "extra": extra, 186 | "payer_details": payer_details, 187 | "lifetime": lifetime, 188 | } 189 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 190 | 191 | return CreatePayment(**response) 192 | 193 | async def get_payment_info(self, invoice_id: str) -> PaymentInfo: 194 | """Get info about payment. 195 | 196 | Docs: https://docs.crystalpay.io/metody-api/invoice-platezhi/poluchenie-informacii-ob-invoise 197 | 198 | :param invoice_id: Invoice ID""" 199 | 200 | url = f'{self.__base_url}/invoice/info/' 201 | 202 | params = { 203 | "auth_login": self.__login, 204 | "auth_secret": self.__secret, 205 | "id": invoice_id, 206 | } 207 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 208 | 209 | return PaymentInfo(**response) 210 | 211 | async def create_payoff(self, amount: Union[int, float], method: str, wallet: str, subtract_from: str, 212 | amount_currency: Optional[str] = None, callback_url: Optional[str] = None, 213 | extra: Optional[str] = None, wallet_extra: Optional[str] = None) -> PayoffCreate: 214 | """Create payoff request. 215 | 216 | Docs: https://docs.crystalpay.io/metody-api/payoff-vyvody/sozdanie-vyvoda 217 | 218 | :param amount: Payoff amount, for example: 10, 0.0015 219 | :param amount_currency: The currency of the amount is automatically converted into the currency of the withdrawal method, for example: RUB, USD, BTC 220 | :param method: Payoff method, for example: LZTMARKET, BITCOIN 221 | :param wallet: Recipient's wallet details 222 | :param subtract_from: Where to write off the commission amount, possible options: balance, amount 223 | :param callback_url: Link for HTTP Callback notification after output is complete 224 | :param extra: Any internal data, for example: Payment ID in your system 225 | :param wallet_extra: Optional. Additional information about the recipient's details. 226 | 227 | More about subtract_from: 228 | 229 | amount - The commission will be deducted from the withdrawal amount. The amount will be credited to your wallet. 230 | balance - The commission will be deducted from the balance. The exact amount will be sent to your wallet.""" 231 | 232 | url = f'{self.__base_url}/payoff/create/' 233 | 234 | signature = hashlib.sha1(str.encode(f"{amount}:{method}:{wallet}:{self.__salt}")).hexdigest() 235 | 236 | params = { 237 | "auth_login": self.__login, 238 | "auth_secret": self.__secret, 239 | "signature": signature, 240 | "amount": amount, 241 | "amount_currency": amount_currency, 242 | "method": method, 243 | "wallet": wallet, 244 | "wallet_extra": wallet_extra, 245 | "subtract_from": subtract_from, 246 | "callback_url": callback_url, 247 | "extra": extra, 248 | } 249 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 250 | 251 | return PayoffCreate(**response) 252 | 253 | async def submit_payoff(self, payoff_id: str) -> PayoffRequest: 254 | """Submit payoff request 255 | 256 | Docs: https://docs.crystalpay.io/metody-api/payoff-vyvody/podtverzhdenie-vyvoda 257 | 258 | :param payoff_id: Payoff ID""" 259 | 260 | signature = hashlib.sha1(str.encode(f"{payoff_id}:{self.__salt}")).hexdigest() 261 | 262 | url = f"{self.__base_url}/payoff/submit/" 263 | 264 | params = { 265 | "auth_login": self.__login, 266 | "auth_secret": self.__secret, 267 | "signature": signature, 268 | "id": payoff_id, 269 | } 270 | 271 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 272 | 273 | return PayoffRequest(**response) 274 | 275 | 276 | async def cancel_payoff(self, payoff_id: str) -> PayoffRequest: 277 | """Cancel payoff request 278 | 279 | Docs: https://docs.crystalpay.io/metody-api/payoff-vyvody/otmena-vyvoda 280 | 281 | :param payoff_id: Payoff ID""" 282 | 283 | signature = hashlib.sha1(str.encode(f"{payoff_id}:{self.__salt}")).hexdigest() 284 | 285 | url = f"{self.__base_url}/payoff/cancel/" 286 | 287 | params = { 288 | "auth_login": self.__login, 289 | "auth_secret": self.__secret, 290 | "signature": signature, 291 | "id": payoff_id, 292 | } 293 | 294 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 295 | 296 | return PayoffRequest(**response) 297 | 298 | async def get_payoff(self, payoff_id: str) -> PayoffRequest: 299 | """Get info about payoff request 300 | 301 | Docs: https://docs.crystalpay.io/metody-api/payoff-vyvody/poluchenie-informacii-o-vyvode 302 | 303 | :param payoff_id: Payoff ID""" 304 | 305 | url = f"{self.__base_url}/payoff/info/" 306 | 307 | params = { 308 | "auth_login": self.__login, 309 | "auth_secret": self.__secret, 310 | "id": payoff_id, 311 | } 312 | 313 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 314 | 315 | return PayoffRequest(**response) 316 | 317 | async def get_tickers_list(self) -> list: 318 | """Get a list of available currencies 319 | 320 | Dosc: https://docs.crystalpay.io/api/valyuty/poluchenie-spiska-dostupnykh-valyut""" 321 | 322 | url = f"{self.__base_url}/ticker/list/" 323 | 324 | params = { 325 | "auth_login": self.__login, 326 | "auth_secret": self.__secret, 327 | } 328 | 329 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 330 | 331 | return list(response['tickers']) 332 | 333 | async def get_tickers_rate(self, tickers: list, base_currency: Optional[str] = "RUB") -> TickersRate: 334 | """Get the exchange rate against 335 | 336 | Docs: https://docs.crystalpay.io/api/valyuty/poluchenie-kursa-valyut 337 | 338 | :param tickers: Array of currencies, for example: [“BTC”, “LTC”] 339 | :param base_currency: Base currency, RUB by default.""" 340 | 341 | url = f"{self.__base_url}/ticker/get/" 342 | 343 | params = { 344 | "auth_login": self.__login, 345 | "auth_secret": self.__secret, 346 | "tickers": tickers, 347 | "base_currency": base_currency, 348 | } 349 | 350 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 351 | 352 | return TickersRate(**response) 353 | 354 | async def get_list_swap_pairs(self, page: Optional[int] = 1, items: Optional[int] = 20, source: Optional[str] = None, 355 | target: Optional[str] = None) -> List[SwapPair]: 356 | """Getting a list of swap pairs. 357 | 358 | Docs: https://docs.crystalpay.io/metody-api/swap-obmeny/obmennye-pary/poluchenie-spiska-obmennykh-par 359 | 360 | :param page: Optional. Page Number. Default is 1. 361 | :param items: Optional. Number of items per page. Default is 20. 362 | :param source: Optional. The original currency, deducted during the exchange. Filter by source. 363 | :param target: Optional. The currency received is credited during the exchange. Filter by target. 364 | """ 365 | 366 | url = f"{self.__base_url}/swap/pair/list/" 367 | 368 | params = { 369 | "auth_login": self.__login, 370 | "auth_secret": self.__secret, 371 | "page": page, 372 | "items": items, 373 | "source": source, 374 | "target": target, 375 | } 376 | self._delete_empty_fields(params) 377 | 378 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 379 | 380 | return [SwapPair(**swapPair) for swapPair in response['items'].values()] 381 | 382 | async def get_swap_pair(self, pair_id: int) -> SwapPair: 383 | """Get a swap pair. 384 | 385 | Docs: https://docs.crystalpay.io/metody-api/swap-obmeny/obmennye-pary/poluchenie-obmennoi-pary 386 | 387 | :param pair_id: ID of the swap pair. 388 | """ 389 | 390 | url = f"{self.__base_url}/swap/pair/get/" 391 | 392 | params = { 393 | "auth_login": self.__login, 394 | "auth_secret": self.__secret, 395 | "pair_id": pair_id, 396 | } 397 | 398 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 399 | 400 | return SwapPair(**response) 401 | 402 | async def create_swap(self, pair_id: int, amount: int, amount_type: str) -> CreateSwap: 403 | """Create swap. 404 | 405 | Docs: https://docs.crystalpay.io/metody-api/swap-obmeny/sozdanie-obmena 406 | 407 | :param pair_id: ID of the swap pair. 408 | :param amount: Amount of the swap. 409 | :param amount_type: Type of the amount. source - The amount specified in the original currency. target - The amount specified in the received currency. 410 | """ 411 | 412 | url = f"{self.__base_url}/swap/create/" 413 | signature = hashlib.sha1(str.encode(f"{amount}:{pair_id}:{self.__salt}")).hexdigest() 414 | 415 | params = { 416 | "auth_login": self.__login, 417 | "auth_secret": self.__secret, 418 | "pair_id": pair_id, 419 | "amount": amount, 420 | "amount_type": amount_type, 421 | "signature": signature, 422 | } 423 | 424 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 425 | 426 | return CreateSwap(**response) 427 | 428 | async def swap_submit(self, swap_id: str) -> SwapInfo: 429 | """Submit swap request. 430 | 431 | Docs: https://docs.crystalpay.io/metody-api/swap-obmeny/podtverzhdenie-obmena 432 | 433 | :param swap_id: ID of the swap. 434 | """ 435 | 436 | url = f"{self.__base_url}/swap/submit/" 437 | signature = hashlib.sha1(str.encode(f"{swap_id}:{self.__salt}")).hexdigest() 438 | 439 | params = { 440 | "auth_login": self.__login, 441 | "auth_secret": self.__secret, 442 | "id": swap_id, 443 | "signature": signature, 444 | } 445 | 446 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 447 | 448 | return SwapInfo(**response) 449 | 450 | async def swap_cancel(self, swap_id: str) -> SwapInfo: 451 | """Cancel swap request. 452 | 453 | Docs: https://docs.crystalpay.io/metody-api/swap-obmeny/otmena-obmena 454 | 455 | :param swap_id: ID of the swap. 456 | """ 457 | 458 | url = f"{self.__base_url}/swap/cancel/" 459 | signature = hashlib.sha1(str.encode(f"{swap_id}:{self.__salt}")).hexdigest() 460 | 461 | params = { 462 | "auth_login": self.__login, 463 | "auth_secret": self.__secret, 464 | "id": swap_id, 465 | "signature": signature, 466 | } 467 | 468 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 469 | 470 | return SwapInfo(**response) 471 | 472 | async def get_swap_info(self, swap_id: str) -> SwapInfo: 473 | """Get swap info. 474 | 475 | Docs: https://docs.crystalpay.io/metody-api/swap-obmeny/poluchenie-informacii-ob-obmene 476 | 477 | :param swap_id: ID of the swap. 478 | """ 479 | 480 | url = f"{self.__base_url}/swap/info/" 481 | 482 | 483 | params = { 484 | "auth_login": self.__login, 485 | "auth_secret": self.__secret, 486 | "id": swap_id, 487 | } 488 | 489 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 490 | 491 | return SwapInfo(**response) 492 | 493 | async def create_transfer(self, method: str, amount: str, receiver: str, 494 | description: Optional[str] = None) -> CreateTransfer: 495 | """Create a transfer. 496 | 497 | Docs: https://docs.crystalpay.io/metody-api/transfer-perevody/sozdanie-perevoda 498 | 499 | :param method: The internal name of the method. 500 | :param amount: Amount of the transfer. 501 | :param receiver: The recipient's cashier's login. 502 | :param description: Optional. Description of the transfer. 503 | """ 504 | 505 | url = f"{self.__base_url}/transfer/create/" 506 | signature = hashlib.sha1(str.encode(f"{amount}:{method}:{receiver}:{self.__salt}")).hexdigest() 507 | 508 | params = { 509 | "auth_login": self.__login, 510 | "auth_secret": self.__secret, 511 | "method": method, 512 | "amount": amount, 513 | "receiver": receiver, 514 | "signature": signature, 515 | "description": description, 516 | } 517 | 518 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 519 | 520 | return CreateTransfer(**response) 521 | 522 | async def submit_transfer(self, transfer_id: str) -> TransferInfo: 523 | """Submit the transfer. 524 | 525 | Docs: https://docs.crystalpay.io/metody-api/transfer-perevody/podtverzhdenie-perevoda 526 | 527 | :param transfer_id: ID of the transfer. 528 | """ 529 | 530 | url = f"{self.__base_url}/transfer/submit/" 531 | signature = hashlib.sha1(str.encode(f"{transfer_id}:{self.__salt}")).hexdigest() 532 | 533 | params = { 534 | "auth_login": self.__login, 535 | "auth_secret": self.__secret, 536 | "id": transfer_id, 537 | "signature": signature, 538 | } 539 | 540 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 541 | 542 | return TransferInfo(**response) 543 | 544 | async def cancel_transfer(self, transfer_id: str) -> TransferInfo: 545 | """Cancel the transfer. 546 | 547 | Docs: https://docs.crystalpay.io/metody-api/transfer-perevody/otmena-perevoda 548 | 549 | :param transfer_id: ID of the transfer. 550 | """ 551 | 552 | url = f"{self.__base_url}/transfer/submit/" 553 | signature = hashlib.sha1(str.encode(f"{transfer_id}:{self.__salt}")).hexdigest() 554 | 555 | params = { 556 | "auth_login": self.__login, 557 | "auth_secret": self.__secret, 558 | "id": transfer_id, 559 | "signature": signature, 560 | } 561 | 562 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 563 | 564 | return TransferInfo(**response) 565 | 566 | async def get_transfer_info(self, transfer_id: str) -> TransferInfo: 567 | """Get info about the transfer. 568 | 569 | Docs: https://docs.crystalpay.io/metody-api/transfer-perevody/poluchenie-informacii-o-perevode 570 | 571 | :param transfer_id: ID of the transfer. 572 | """ 573 | 574 | url = f"{self.__base_url}/transfer/info/" 575 | 576 | params = { 577 | "auth_login": self.__login, 578 | "auth_secret": self.__secret, 579 | "id": transfer_id, 580 | } 581 | 582 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 583 | 584 | return TransferInfo(**response) 585 | 586 | async def get_history_payments(self, page: Optional[int] = 1, items: Optional[int] = 20, period: Optional[int] = 1, 587 | export_csv: Optional[bool] = False) -> List[PaymentInfo]: 588 | """Get payments history. 589 | 590 | Docs: https://docs.crystalpay.io/metody-api/report-otchyoty-i-statistika/invoice-platezhi/poluchenie-istorii 591 | 592 | :param page: Optional. Page number. Default is 1. 593 | :param items: Optional. Number of items per page. Default is 20. 594 | :param period: Optional. The period from the current date, in days. Default is 1. 595 | :param export_csv: Optional. Export as a csv format table. Default is False. 596 | """ 597 | 598 | url = f"{self.__base_url}/report/invoice/history/" 599 | 600 | params = { 601 | "auth_login": self.__login, 602 | "auth_secret": self.__secret, 603 | "page": page, 604 | "items": items, 605 | "period": period, 606 | "export_csv": export_csv, 607 | } 608 | 609 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 610 | 611 | if response["items"]: 612 | return [PaymentInfo(**payment) for payment in response['items']] 613 | else: 614 | return [] 615 | 616 | async def get_stats_payments(self, period: Optional[int] = 1, 617 | export_pdf: Optional[bool] = False) -> Stats: 618 | """Get payments stats. 619 | 620 | Docs: https://docs.crystalpay.io/metody-api/report-otchyoty-i-statistika/invoice-platezhi/poluchenie-statistiki 621 | 622 | :param period: Optional. The period from the current date, in days. Default is 1. 623 | :param export_pdf: Optional. Export as a pdf format. Default is False. 624 | """ 625 | 626 | url = f"{self.__base_url}/report/invoice/summary/" 627 | 628 | params = { 629 | "auth_login": self.__login, 630 | "auth_secret": self.__secret, 631 | "period": period, 632 | "export_pdf": export_pdf, 633 | } 634 | 635 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 636 | 637 | return Stats(**response) 638 | 639 | async def get_history_payoffs(self, page: Optional[int] = 1, items: Optional[int] = 20, period: Optional[int] = 1, 640 | export_csv: Optional[bool] = False) -> List[PayoffRequest]: 641 | """Get payoffs history. 642 | 643 | Docs: https://docs.crystalpay.io/metody-api/report-otchyoty-i-statistika/payoff-vyvody/poluchenie-istorii 644 | 645 | :param page: Optional. Page number. Default is 1. 646 | :param items: Optional. Number of items per page. Default is 20. 647 | :param period: Optional. The period from the current date, in days. Default is 1. 648 | :param export_csv: Optional. Export as a csv format table. Default is False. 649 | """ 650 | 651 | url = f"{self.__base_url}/report/payoff/history/" 652 | 653 | params = { 654 | "auth_login": self.__login, 655 | "auth_secret": self.__secret, 656 | "page": page, 657 | "items": items, 658 | "period": period, 659 | "export_csv": export_csv, 660 | } 661 | 662 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 663 | 664 | if response['items']: 665 | return [PayoffRequest(**payment) for payment in response['items']] 666 | else: 667 | return [] 668 | 669 | async def get_stats_payoffs(self, period: Optional[int] = 1, 670 | export_pdf: Optional[bool] = False) -> Stats: 671 | """Get payoff stats. 672 | 673 | Docs: https://docs.crystalpay.io/metody-api/report-otchyoty-i-statistika/payoff-vyvody/poluchenie-statistiki 674 | 675 | :param period: Optional. The period from the current date, in days. Default is 1. 676 | :param export_pdf: Optional. Export as a pdf format. Default is False. 677 | """ 678 | 679 | url = f"{self.__base_url}/report/payoff/summary/" 680 | 681 | params = { 682 | "auth_login": self.__login, 683 | "auth_secret": self.__secret, 684 | "period": period, 685 | "export_pdf": export_pdf, 686 | } 687 | 688 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 689 | 690 | return Stats(**response) 691 | 692 | 693 | async def get_history_swaps(self, page: Optional[int] = 1, items: Optional[int] = 20, period: Optional[int] = 1, 694 | export_csv: Optional[bool] = False) -> List[SwapInfo]: 695 | """Get swaps history. 696 | 697 | Docs: https://docs.crystalpay.io/metody-api/report-otchyoty-i-statistika/swap-obmeny/poluchenie-istorii 698 | 699 | :param page: Optional. Page number. Default is 1. 700 | :param items: Optional. Number of items per page. Default is 20. 701 | :param period: Optional. The period from the current date, in days. Default is 1. 702 | :param export_csv: Optional. Export as a csv format table. Default is False. 703 | """ 704 | 705 | url = f"{self.__base_url}/report/swap/history/" 706 | 707 | params = { 708 | "auth_login": self.__login, 709 | "auth_secret": self.__secret, 710 | "page": page, 711 | "items": items, 712 | "period": period, 713 | "export_csv": export_csv, 714 | } 715 | 716 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 717 | 718 | if response["items"]: 719 | return [SwapInfo(**payment) for payment in response['items']] 720 | else: 721 | return [] 722 | 723 | async def get_history_transfers(self, page: Optional[int] = 1, items: Optional[int] = 20, period: Optional[int] = 1, 724 | export_csv: Optional[bool] = False) -> List[TransferInfo]: 725 | """Get swaps history. 726 | 727 | Docs: https://docs.crystalpay.io/metody-api/report-otchyoty-i-statistika/transfer-perevody/poluchenie-istorii 728 | 729 | :param page: Optional. Page number. Default is 1. 730 | :param items: Optional. Number of items per page. Default is 20. 731 | :param period: Optional. The period from the current date, in days. Default is 1. 732 | :param export_csv: Optional. Export as a csv format table. Default is False. 733 | """ 734 | 735 | url = f"{self.__base_url}/report/transfer/history/" 736 | 737 | params = { 738 | "auth_login": self.__login, 739 | "auth_secret": self.__secret, 740 | "page": page, 741 | "items": items, 742 | "period": period, 743 | "export_csv": export_csv, 744 | } 745 | 746 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 747 | 748 | if response["items"]: 749 | return [TransferInfo(**payment) for payment in response['items']] 750 | else: 751 | return [] 752 | -------------------------------------------------------------------------------- /AsyncPayments/crystalPay/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | from typing import Optional 3 | 4 | 5 | class CassaInfo(BaseModel): 6 | id: int 7 | name: str 8 | status_level: int 9 | created_at: str 10 | 11 | 12 | class BalanceListField(BaseModel): 13 | name: str 14 | amount: str 15 | currency: str 16 | amount_accuracy: int 17 | 18 | 19 | class Method(BaseModel): 20 | name: str 21 | currency: str 22 | amount_accuracy: int 23 | minimal_status_level: int 24 | settings: dict 25 | in_: Optional[dict] = Field(alias="in", default=None) 26 | out: Optional[dict] = None 27 | 28 | 29 | class Methods(BaseModel): 30 | BITCOIN: Method 31 | BITCOINCASH: Method 32 | BNBCRYPTOBOT: Method 33 | BNBSMARTCHAIN: Method 34 | BTCCRYPTOBOT: Method 35 | CARDRUBP2P: Method 36 | DASH: Method 37 | DOGECOIN: Method 38 | ETHCRYPTOBOT: Method 39 | ETHEREUM: Method 40 | LITECOIN: Method 41 | LTCCRYPTOBOT: Method 42 | LZTMARKET: Method 43 | POLYGON: Method 44 | SBERPAYP2P: Method 45 | SBPP2P: Method 46 | TONCOIN: Method 47 | TONCRYPTOBOT: Method 48 | TRON: Method 49 | USDCTRC: Method 50 | USDTCRYPTOBOT: Method 51 | USDTTRC: Method 52 | 53 | 54 | class BalancesList(BaseModel): 55 | BITCOIN: BalanceListField 56 | BITCOINCASH: BalanceListField 57 | BNBCRYPTOBOT: BalanceListField 58 | BNBSMARTCHAIN: BalanceListField 59 | BTCCRYPTOBOT: BalanceListField 60 | CARDRUBP2P: BalanceListField 61 | DASH: BalanceListField 62 | DOGECOIN: BalanceListField 63 | ETHCRYPTOBOT: BalanceListField 64 | ETHEREUM: BalanceListField 65 | LITECOIN: BalanceListField 66 | LTCCRYPTOBOT: BalanceListField 67 | LZTMARKET: BalanceListField 68 | POLYGON: BalanceListField 69 | SBERPAYP2P: BalanceListField 70 | SBPP2P: BalanceListField 71 | TONCOIN: BalanceListField 72 | TONCRYPTOBOT: BalanceListField 73 | TRON: BalanceListField 74 | USDCTRC: BalanceListField 75 | USDTCRYPTOBOT: BalanceListField 76 | USDTTRC: BalanceListField 77 | 78 | 79 | class CreatePayment(BaseModel): 80 | id: str 81 | url: str 82 | type_: str = Field(alias="type") 83 | rub_amount: str 84 | 85 | 86 | class Balance(BaseModel): 87 | method: str 88 | name: str 89 | amount: str 90 | currency: str 91 | amount_accuracy: int 92 | 93 | 94 | class PaymentInfo(BaseModel): 95 | id: str 96 | url: str 97 | state: str 98 | type_: str = Field(alias="type") 99 | method: Optional[str] = None 100 | required_method: Optional[str] = None 101 | amount_currency: str 102 | rub_amount: str 103 | initial_amount: str 104 | remaining_amount: str 105 | balance_amount: str 106 | commission_amount: str 107 | description: Optional[str] = None 108 | redirect_url: Optional[str] = None 109 | callback_url: Optional[str] = None 110 | extra: Optional[str] = None 111 | created_at: str 112 | expired_at: str 113 | final_at: Optional[str] = None 114 | 115 | 116 | class PayoffCreate(BaseModel): 117 | id: str 118 | method: str 119 | commission_amount: str 120 | amount: str 121 | rub_amount: str 122 | receive_amount: str 123 | deduction_amount: str 124 | subtract_from: str 125 | amount_currency: str 126 | wallet: str 127 | 128 | 129 | class PayoffRequest(BaseModel): 130 | id: str 131 | state: str 132 | method: str 133 | amount: str 134 | amount_currency: str 135 | commission_amount: str 136 | rub_amount: str 137 | receive_amount: str 138 | deduction_amount: str 139 | subtract_from: str 140 | wallet: str 141 | message: Optional[str] = None 142 | callback_url: Optional[str] = None 143 | extra: Optional[str] = None 144 | created_at: str 145 | final_at: Optional[str] = None 146 | 147 | 148 | class SwapPair(BaseModel): 149 | pair_id: Optional[int] = None 150 | source: dict 151 | target: dict 152 | price: str 153 | 154 | 155 | class CreateSwap(BaseModel): 156 | id: str 157 | pair_id: int 158 | amount_type: str 159 | amount: str 160 | source: dict 161 | target: dict 162 | price: str 163 | 164 | 165 | class SwapInfo(BaseModel): 166 | id: str 167 | state: str 168 | pair_id: int 169 | amount_type: str 170 | amount: str 171 | source: dict 172 | target: dict 173 | price: str 174 | created_at: str 175 | expired_at: str 176 | final_at: Optional[str] = None 177 | 178 | 179 | class TickersRate(BaseModel): 180 | base_currency: str 181 | currencies: dict 182 | 183 | 184 | class CreateTransfer(BaseModel): 185 | id: int 186 | method: str 187 | amount_currency: str 188 | amount: str 189 | sender: str 190 | receiver: str 191 | 192 | 193 | class TransferInfo(BaseModel): 194 | id: int 195 | state: str 196 | type_: str = Field(alias="type") 197 | method: str 198 | amount_currency: str 199 | amount: str 200 | sender: str 201 | receiver: str 202 | description: Optional[str] = None 203 | created_at: str 204 | final_at: str 205 | 206 | 207 | class Stats(BaseModel): 208 | payed_rub_amount: str 209 | payed_count: int 210 | total_count: int 211 | conversion_percent: int 212 | -------------------------------------------------------------------------------- /AsyncPayments/exceptions/__init__.py: -------------------------------------------------------------------------------- 1 | from .exceptions import BadRequest, RequestError, MissingScopeError 2 | -------------------------------------------------------------------------------- /AsyncPayments/exceptions/exceptions.py: -------------------------------------------------------------------------------- 1 | class BadRequest(Exception): 2 | pass 3 | 4 | 5 | class RequestError(Exception): 6 | pass 7 | 8 | 9 | class MissingScopeError(Exception): 10 | pass 11 | -------------------------------------------------------------------------------- /AsyncPayments/freeKassa/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import AsyncFreeKassa -------------------------------------------------------------------------------- /AsyncPayments/freeKassa/api.py: -------------------------------------------------------------------------------- 1 | from ..requests import RequestsClient 2 | from typing import Optional, Union, List 3 | from .models import Balance, Order, Orders, CreateOrder, Currency, WithdrawalCurrency, Store, Withdrawal, Withdrawals, CreateWithdrawal 4 | 5 | import json 6 | import hashlib 7 | import time 8 | import hmac 9 | 10 | 11 | class AsyncFreeKassa(RequestsClient): 12 | API_HOST: str = "https://freekassa.com/" 13 | 14 | def __init__(self, apiKey: str, shopId: int) -> None: 15 | """ 16 | Initialize FreeKassa API client 17 | :param apiKey: Your api key 18 | :param shopId: Your shop id 19 | """ 20 | super().__init__() 21 | self.__apiKey = apiKey 22 | self.__shopId = shopId 23 | self.__headers = { 24 | 'Content-Type': 'application/json', 25 | } 26 | self.__base_url = "https://api.freekassa.com/v1" 27 | self.__post_method = "POST" 28 | self.__payment_name = "freeKassa" 29 | self.check_values() 30 | 31 | def check_values(self): 32 | if not self.__shopId or not self.__apiKey: 33 | raise ValueError('No ShopID or ApiKey specified') 34 | 35 | def __generate_sign(self, data: dict) -> str: 36 | data = dict(sorted(data.items())) 37 | return hmac.new(self.__apiKey.encode(), '|'.join(map(str, data.values())).encode(), hashlib.sha256).hexdigest() 38 | 39 | async def get_balance(self) -> List[Balance]: 40 | """Get balance or your store. 41 | 42 | Docs: https://docs.freekassa.com/#operation/getBalance 43 | """ 44 | url = f"{self.__base_url}/balance" 45 | 46 | params = { 47 | "shopId": self.__shopId, 48 | "nonce": time.time_ns(), 49 | } 50 | params['signature'] = self.__generate_sign(params) 51 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 52 | 53 | return [Balance(**balance) for balance in response['balance']] 54 | 55 | async def get_orders(self, orderId: Optional[int] = None, paymentId: Optional[str] = None, 56 | orderStatus: Optional[int] = None, dateFrom: Optional[str] = None, 57 | dateTo: Optional[str] = None, page: Optional[int] = None) -> Orders: 58 | """Get orders of your store. 59 | 60 | Docs: https://docs.freekassa.com/#operation/getOrders 61 | 62 | :param orderId: Optional. Freekassa Order Number. Example: orderId=123456789. 63 | :param paymentId: Optional. The order number in your store. Example: paymentId=987654321. 64 | :param orderStatus: Optional. Order status. Example: orderStatus=1. 65 | :param dateFrom: Optional. Date from. Example: dateFrom=2021-01-01 13:45:21. 66 | :param dateTo: Optional. Date by. Example: dateTo=2021-01-02 13:45:21. 67 | :param page: Optional. Page number. 68 | """ 69 | url = f"{self.__base_url}/orders" 70 | params = { 71 | "shopId": self.__shopId, 72 | "nonce": time.time_ns(), 73 | "orderId": orderId, 74 | "paymentId": paymentId, 75 | "orderStatus": orderStatus, 76 | "dateFrom": dateFrom, 77 | "dateTo": dateTo, 78 | "page": page, 79 | } 80 | self._delete_empty_fields(params) 81 | params['signature'] = self.__generate_sign(params) 82 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 83 | 84 | return Orders(pages=int(response['pages']), orders=[Order(**order) for order in response["orders"]]) 85 | 86 | async def create_order(self, i: int, email: str, ip: str, amount: Union[int, float], currency: str, 87 | tel: Optional[str] = None, paymentId: Optional[str] = None, 88 | successUrl: Optional[str] = None, failureUrl: Optional[str] = None, 89 | notificationUrl: Optional[str] = None) -> CreateOrder: 90 | """Create an order and receive a payment link. 91 | 92 | Docs: https://docs.freekassa.com/#operation/createOrder 93 | 94 | :param i: Required. Payment system ID. Example: i=6. 95 | :param email: Required. Buyer's email address. Example: email=user@site.ru. 96 | :param ip: Required. Buyer's IP address. Example: ip=0.0.0.0. 97 | :param amount: Required. Payment amount. Example: amount=100.23. 98 | :param currency: Required. Payment currency. Example: currency=RUB. 99 | :param tel: Optional. The payer's phone number is required in some payment methods. Example: tel=+79261231212. 100 | :param paymentId: Optional. Payment system ID. Example: paymentId=987654321. 101 | :param successUrl: Optional. Redefining the success url (to enable this parameter, contact support). Example: successUrl=https://site.ru/success. 102 | :param failureUrl: Optional. Redefining the error URL (to enable this parameter, contact support). Example: failureUrl=https://site.ru/error. 103 | :param notificationUrl: Optional. Redefining the notification url (to enable this option, contact support). Example: notificationUrl=https://site.ru/notify. 104 | """ 105 | url = f"{self.__base_url}/orders/create" 106 | params = { 107 | "shopId": self.__shopId, 108 | "nonce": time.time_ns(), 109 | "i": i, 110 | "email": email, 111 | "ip": ip, 112 | "amount": amount, 113 | "currency": currency, 114 | "tel": tel, 115 | "paymentId": paymentId, 116 | "success_url": successUrl, 117 | "failure_url": failureUrl, 118 | "notification_url": notificationUrl, 119 | } 120 | self._delete_empty_fields(params) 121 | params['signature'] = self.__generate_sign(params) 122 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 123 | return CreateOrder(**response) 124 | 125 | async def get_list_of_currencies(self) -> List[Currency]: 126 | """Get list of all available currencies for payments. 127 | 128 | Docs: https://docs.freekassa.com/#operation/getCurrencies 129 | """ 130 | url = f"{self.__base_url}/currencies" 131 | params = { 132 | "shopId": self.__shopId, 133 | "nonce": time.time_ns(), 134 | } 135 | params["signature"] = self.__generate_sign(params) 136 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 137 | 138 | return [Currency(**currency) for currency in response['currencies']] 139 | 140 | async def check_currency_status(self, paymentId: int) -> bool: 141 | """Check the availability of the payment system for payment. 142 | 143 | Docs: https://docs.freekassa.com/#operation/currencyStatus 144 | 145 | :return: True - Payment is available. False - Payment is not available. 146 | """ 147 | url = f"{self.__base_url}/currencies/{paymentId}/status" 148 | params = { 149 | "shopId": self.__shopId, 150 | "nonce": time.time_ns(), 151 | } 152 | params["signature"] = self.__generate_sign(params) 153 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 154 | 155 | return response['type'] == "success" 156 | 157 | async def get_list_of_currencies_for_withdrawal(self) -> List[WithdrawalCurrency]: 158 | """Get list of all available currencies for withdrawal. 159 | 160 | Docs: https://docs.freekassa.com/#operation/getWithdrawalsCurrencies 161 | """ 162 | url = f"{self.__base_url}/withdrawals/currencies" 163 | params = { 164 | "shopId": self.__shopId, 165 | "nonce": time.time_ns(), 166 | } 167 | params["signature"] = self.__generate_sign(params) 168 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 169 | 170 | return [WithdrawalCurrency(**currency) for currency in response['currencies']] 171 | 172 | async def get_list_of_your_stores(self) -> List[Store]: 173 | """Get list of your stores. 174 | 175 | Docs: https://docs.freekassa.com/#operation/getShops 176 | """ 177 | url = f"{self.__base_url}/shops" 178 | params = { 179 | "shopId": self.__shopId, 180 | "nonce": time.time_ns(), 181 | } 182 | params["signature"] = self.__generate_sign(params) 183 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 184 | 185 | return [Store(**store) for store in response['shops']] 186 | 187 | async def get_withdrawals(self, orderId: Optional[int] = None, paymentId: Optional[str] = None, 188 | orderStatus: Optional[int] = None, dateFrom: Optional[str] = None, 189 | dateTo: Optional[str] = None, page: Optional[int] = None) -> Withdrawals: 190 | """Get list of withdrawals. 191 | 192 | Docs: https://docs.freekassa.com/#operation/getWithdrawals 193 | 194 | :param orderId: Optional. Freekassa Order Number. Example: orderId=123456789. 195 | :param paymentId: Optional. The order number in your store. Example: paymentId=987654321. 196 | :param orderStatus: Optional. Order status. Example: orderStatus=1. 197 | :param dateFrom: Optional. Date from. Example: dateFrom=2021-01-01 13:45:21. 198 | :param dateTo: Optional. Date by. Example: dateTo=2021-01-02 13:45:21. 199 | :param page: Optional. Page number. 200 | """ 201 | url = f"{self.__base_url}/withdrawals" 202 | params = { 203 | "shopId": self.__shopId, 204 | "nonce": time.time_ns(), 205 | "orderId": orderId, 206 | "paymentId": paymentId, 207 | "orderStatus": orderStatus, 208 | "dateFrom": dateFrom, 209 | "dateTo": dateTo, 210 | "page": page, 211 | } 212 | self._delete_empty_fields(params) 213 | params['signature'] = self.__generate_sign(params) 214 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 215 | 216 | return Withdrawals(pages=int(response['pages']), withdrawals=[Withdrawal(**withdrawal) for withdrawal in response["orders"]]) 217 | 218 | async def create_withdrawal(self, i: int, account: str, amount: Union[int, float], currency: str, 219 | paymentId: Optional[str] = None) -> CreateWithdrawal: 220 | """Create withdrawal. 221 | 222 | Docs: https://docs.freekassa.com/#operation/createWithdrawal 223 | 224 | :param i: Required. Payment system ID. Example: i=6. 225 | :param account: Required. A wallet for crediting funds (when paying to FKWallet, withdrawal is made only to your account). Example: account=5500000000000004. 226 | :param amount: Required. Payment amount. Example: amount=100.23. 227 | :param currency: Required. Payment currency. Example: currency=RUB. 228 | :param paymentId: Optional. Payment system ID. Example: paymentId=987654321. 229 | """ 230 | url = f"{self.__base_url}/withdrawals/create" 231 | params = { 232 | "shopId": self.__shopId, 233 | "nonce": time.time_ns(), 234 | "i": i, 235 | "account": account, 236 | "amount": amount, 237 | "currency": currency, 238 | "paymentId": paymentId, 239 | } 240 | self._delete_empty_fields(params) 241 | params['signature'] = self.__generate_sign(params) 242 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, data=json.dumps(params)) 243 | return CreateWithdrawal(**response['data']) 244 | -------------------------------------------------------------------------------- /AsyncPayments/freeKassa/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import Optional, List, Union 3 | 4 | 5 | class Balance(BaseModel): 6 | currency: str 7 | value: Union[int, str, float] 8 | 9 | 10 | class Order(BaseModel): 11 | merchant_order_id: str 12 | fk_order_id: int 13 | amount: Union[int, float] 14 | currency: str 15 | email: str 16 | account: Optional[str] = None 17 | date: str 18 | status: int 19 | payer_account: Optional[str] = None 20 | 21 | 22 | class Orders(BaseModel): 23 | pages: int 24 | orders: List[Order] 25 | 26 | 27 | class CreateOrder(BaseModel): 28 | orderId: int 29 | orderHash: str 30 | location: str 31 | 32 | 33 | class Currency(BaseModel): 34 | id: int 35 | name: str 36 | currency: str 37 | is_enabled: int 38 | is_favorite: int 39 | 40 | 41 | class WithdrawalCurrency(BaseModel): 42 | id: int 43 | name: str 44 | min: int 45 | max: int 46 | currency: str 47 | can_exchange: int 48 | 49 | 50 | class Store(BaseModel): 51 | id: int 52 | name: str 53 | url: Optional[str] = None 54 | activated: Optional[int] = None 55 | 56 | 57 | class Withdrawal(BaseModel): 58 | id: int 59 | amount: Union[int, float] 60 | currency: str 61 | ext_currency_id: int 62 | account: str 63 | date: str 64 | status: int 65 | 66 | 67 | class Withdrawals(BaseModel): 68 | pages: int 69 | withdrawals: List[Withdrawal] 70 | 71 | 72 | class CreateWithdrawal(BaseModel): 73 | id: int 74 | -------------------------------------------------------------------------------- /AsyncPayments/lolz/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import AsyncLolzteamMarketPayment -------------------------------------------------------------------------------- /AsyncPayments/lolz/api.py: -------------------------------------------------------------------------------- 1 | from ..requests import RequestsClient 2 | from typing import Optional, Union 3 | from .models import User, Payments, Invoice, Invoices 4 | from ..exceptions import MissingScopeError 5 | 6 | import json 7 | import random 8 | import math 9 | import time 10 | import secrets 11 | import base64 12 | from urllib.parse import urlencode 13 | 14 | 15 | class AsyncLolzteamMarketPayment(RequestsClient): 16 | API_HOST: str = "https://lzt.market" 17 | 18 | def __init__(self, token: str) -> None: 19 | """ 20 | Initialize LolzteamMarket API client 21 | :param token: Your Lolzteam Token 22 | """ 23 | super().__init__() 24 | self.__token = token 25 | jwt_payload = json.loads( 26 | base64.b64decode(token.split(".")[1] + "==").decode("utf-8") 27 | ) 28 | self.__user_id = jwt_payload["sub"] 29 | if jwt_payload.get("scope"): 30 | if "market" not in jwt_payload["scope"]: 31 | raise MissingScopeError( 32 | '"Market" scope is not provided in your token. You need to recreate token with "Market" scope.' 33 | ) 34 | self.__headers = { 35 | "Authorization": f"Bearer {self.__token}", 36 | "Accept": "application/json", 37 | } 38 | self.__base_url = "https://api.lzt.market" 39 | self.__get_method = "GET" 40 | self.__post_method = "POST" 41 | self.__payment_name = "lolz" 42 | 43 | async def get_me(self) -> User: 44 | """Get info about your account on Zelenka (Lolzteam). 45 | 46 | Docs: https://lzt-market.readme.io/reference/marketprofilesettingsgetinfo""" 47 | 48 | url = f"{self.__base_url}/me" 49 | 50 | response = await self._request( 51 | self.__payment_name, self.__get_method, url, headers=self.__headers 52 | ) 53 | 54 | return User(**response["user"]) 55 | 56 | def __get_random_string(self): 57 | return f"{time.time()}_{secrets.token_hex(random.randint(5, 10))}" 58 | 59 | async def create_invoice( 60 | self, 61 | amount: Union[int, float], 62 | payment_id: str, 63 | comment: str, 64 | url_success: str, 65 | merchant_id: str, 66 | currency: Optional[str] = "rub", 67 | url_callback: Optional[str] = None, 68 | lifetime: Optional[int] = 3600, 69 | additional_data: Optional[str] = None 70 | ) -> Invoice: 71 | """Create invoice. 72 | 73 | :param amount: Invoice amount. 74 | :param payment_id: Payment ID in your system (must be unique within the merchant / invoices). 75 | :param comment: Comment to the invoice. 76 | :param url_success: URL to redirect to after successful payment. 77 | :param merchant_id: Merchant ID. 78 | :param currency: Optional. Currency that will be used to create the invoice. Defaults to 'rub'. 79 | :param url_callback: Optional. Callback url. 80 | :param lifetime: Optional. Invoice lifetime. 81 | :param additional_data: Optional. Additional information for you. 82 | 83 | Docs: https://lzt-market.readme.io/reference/paymentsinvoicecreate 84 | """ 85 | params = { 86 | "amount": amount, 87 | "payment_id": payment_id, 88 | "comment": comment, 89 | "url_success": url_success, 90 | "merchant_id": merchant_id, 91 | "currency": currency, 92 | "url_callback": url_callback, 93 | "lifetime": lifetime, 94 | "additional_data": additional_data, 95 | } 96 | self._delete_empty_fields(params) 97 | url = f"{self.__base_url}/invoice?{urlencode(params)}" 98 | 99 | response = await self._request( 100 | self.__payment_name, 101 | self.__post_method, 102 | url, 103 | headers=self.__headers, 104 | ) 105 | return Invoice(**response['invoice']) 106 | 107 | async def get_invoice( 108 | self, 109 | invoice_id: Optional[str] = None, 110 | payment_id: Optional[str] = None 111 | ) -> Invoice: 112 | """Get invoice. 113 | 114 | :param invoice_id: Optional. Invoice ID. 115 | :param payment_id: Optional. Payment ID. 116 | 117 | Docs: https://lzt-market.readme.io/reference/paymentsinvoiceget 118 | """ 119 | 120 | params = { 121 | "invoice_id": invoice_id, 122 | "payment_id": payment_id, 123 | } 124 | 125 | self._delete_empty_fields(params) 126 | 127 | url = f"{self.__base_url}/invoice?{urlencode(params)}" 128 | 129 | response = await self._request( 130 | self.__payment_name, 131 | self.__get_method, 132 | url, 133 | headers=self.__headers, 134 | ) 135 | return Invoice(**response['data']) 136 | 137 | async def get_invoice_list( 138 | self, 139 | page: Optional[int] = 1, 140 | currency: Optional[str] = None, 141 | status: Optional[str] = None, 142 | amount: Optional[Union[float, int]] = None, 143 | merchant_id: Optional[int] = None, 144 | ) -> Invoices: 145 | """Get invoice list. 146 | 147 | :param page: Optional. The number of the page to display results from. 148 | :param currency: Optional. Currency of the created invoice. 149 | :param status: Optional. Status of the invoice. 150 | :param amount: Optional. Invoice amount. 151 | :param merchant_id: Optional. Merchant ID. 152 | 153 | Docs: https://lzt-market.readme.io/reference/paymentsinvoicelist 154 | """ 155 | 156 | url = f"{self.__base_url}/invoice/list" 157 | 158 | params = { 159 | "page": page, 160 | "currency": currency, 161 | "status": status, 162 | "amount": amount, 163 | "merchant_id": merchant_id, 164 | } 165 | 166 | self._delete_empty_fields(params) 167 | 168 | response = await self._request( 169 | self.__payment_name, 170 | self.__get_method, 171 | url, 172 | headers=self.__headers, 173 | params=params, 174 | ) 175 | return Invoices(**response) 176 | 177 | def get_payment_link( 178 | self, 179 | amount: Union[int, float], 180 | comment: Optional[str] = None, 181 | is_hold: Optional[bool] = False, 182 | is_amount_ceiling: Optional[bool] = False, 183 | ) -> str: 184 | """Get a link to transfer funds to the Lolzteam market. To accept payments, it is recommended to use the create_invoice() method. 185 | 186 | :param amount: Amount to transfer 187 | :param comment: Comment on the translation. If not specified: a random unique set of characters is generated. 188 | :param is_hold: If True: The page will have funds holding enabled by default. The user will be able to turn it off. *If you use this link for payment: ask your users not to enable hold!!! Defaults to False 189 | :param is_amount_ceiling: If True: The transfer amount will be rounded up. Defaults to False 190 | 191 | :return: Link to transfer (String)""" 192 | 193 | if is_amount_ceiling: 194 | amount = math.ceil(amount) 195 | 196 | if not comment: 197 | comment = self.__get_random_string() 198 | 199 | return f"https://lzt.market/balance/transfer?user_id={self.__user_id}&hold={int(is_hold)}&amount={amount}&comment={comment}" 200 | 201 | async def get_history_payments( 202 | self, 203 | operation_type: Optional[str] = None, 204 | pmin: Optional[int] = None, 205 | pmax: Optional[int] = None, 206 | page: Optional[int] = 1, 207 | operation_id_lt: Optional[int] = None, 208 | receiver: Optional[str] = None, 209 | sender: Optional[str] = None, 210 | startDate: Optional[str] = None, 211 | endDate: Optional[str] = None, 212 | wallet: Optional[str] = None, 213 | comment: Optional[str] = None, 214 | is_hold: Optional[bool] = None, 215 | show_payment_stats: Optional[bool] = None, 216 | ) -> Payments: 217 | """Displays list of your payments. 218 | 219 | Docs: https://lzt-market.readme.io/reference/paymentslisthistory 220 | 221 | :param operation_type: Optional. Type of operation. It can only be: "income", "cost", "refilled_balance", "withdrawal_balance", "paid_item", "sold_item", "money_transfer", "receiving_money", "internal_purchase", "claim_hold". 222 | :param pmin: Optional. Minimal price of account (Inclusive). 223 | :param pmax: Optional. Maximum price of account (Inclusive). 224 | :param page: Optional. The number of the page to display results from. 225 | :param operation_id_lt: Optional. ID of the operation from which the result begins. 226 | :param receiver: Optional. Username of user, which receive money from you. 227 | :param sender: Optional. Username of user, which sent money to you. 228 | :param startDate: Optional. Start date of operation (RFC 3339 date format). 229 | :param endDate: Optional. End date of operation (RFC 3339 date format). 230 | :param wallet: Optional. Wallet, which used for money payouts. 231 | :param comment: Optional. Comment for money transfers. 232 | :param is_hold: Optional. Display hold operations. 233 | :param show_payment_stats: Optional. Display payment stats for selected period (outgoing value, incoming value). 234 | """ 235 | 236 | url = f"{self.__base_url}/user/{self.__user_id}/payments" 237 | 238 | if is_hold: 239 | is_hold = int(is_hold) 240 | if show_payment_stats: 241 | show_payment_stats = int(show_payment_stats) 242 | 243 | params = { 244 | "type": operation_type, 245 | "pmin": pmin, 246 | "pmax": pmax, 247 | "page": page, 248 | "operation_id_lt": operation_id_lt, 249 | "receiver": receiver, 250 | "sender": sender, 251 | "startDate": startDate, 252 | "endDate": endDate, 253 | "wallet": wallet, 254 | "comment": comment, 255 | "is_hold": is_hold, 256 | "show_payment_stats": show_payment_stats, 257 | } 258 | 259 | self._delete_empty_fields(params) 260 | 261 | response = await self._request( 262 | self.__payment_name, 263 | self.__get_method, 264 | url, 265 | headers=self.__headers, 266 | params=params, 267 | ) 268 | if type(response.get("payments")) is list and len(response.get("payments")) == 0: 269 | response["payments"] = {} 270 | return Payments(**response) 271 | 272 | async def check_status_payment(self, pay_amount: int, comment: str) -> bool: 273 | """Displays whether the transfer is paid or not. 274 | 275 | :param pay_amount: The amount indicated in the transaction. 276 | :param comment: Comment indicated in the transaction. 277 | 278 | :return: True if payment has been received. Otherwise False""" 279 | payments = ( 280 | await self.get_history_payments( 281 | operation_type="receiving_money", 282 | comment=comment, 283 | pmin=pay_amount, 284 | pmax=pay_amount, 285 | ) 286 | ).payments 287 | if payments.values(): 288 | return True 289 | return False 290 | -------------------------------------------------------------------------------- /AsyncPayments/lolz/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import Optional, List, Union 3 | 4 | 5 | class User(BaseModel): 6 | user_id: int 7 | username: str 8 | balance: float 9 | hold: float 10 | 11 | class Payments(BaseModel): 12 | payments: dict 13 | page: int 14 | hasNextPage: bool 15 | 16 | 17 | class Invoice(BaseModel): 18 | amount: Union[float, int] 19 | currency: str 20 | payment_id: str 21 | merchant_id: int 22 | comment: str 23 | additional_data: str 24 | url_success: str 25 | url_callback: str 26 | expires_at: int 27 | user_id: int 28 | invoice_date: int 29 | status: str 30 | paid_date: int 31 | invoice_id: int 32 | url: str 33 | 34 | 35 | class Invoices(BaseModel): 36 | invoices: Optional[List[Invoice]] = [] 37 | count: int 38 | page: int 39 | perPage: int -------------------------------------------------------------------------------- /AsyncPayments/payok/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import AsyncPayOK -------------------------------------------------------------------------------- /AsyncPayments/payok/api.py: -------------------------------------------------------------------------------- 1 | from ..requests import RequestsClient 2 | from typing import Optional, Union, List 3 | from .models import Balance, Transaction, Payout, CreatePayout, PayoutOnCreate 4 | from urllib.parse import urlencode 5 | import hashlib 6 | 7 | 8 | class AsyncPayOK(RequestsClient): 9 | API_HOST: str = "https://payok.io/" 10 | 11 | def __init__(self, apiKey: str, secretKey: str, apiId: int, shopId: int) -> None: 12 | """ 13 | Initialize PayOK API client 14 | :param apiKey: Your api key 15 | :param secretKey: Your secret key 16 | :param apiId: Your api id 17 | :param shopId: Your shop id 18 | """ 19 | super().__init__() 20 | self.__apiKey = apiKey 21 | self.__secretKey = secretKey 22 | self.__apiId = apiId 23 | self.__shopId = shopId 24 | self.__base_url = "https://payok.io/api" 25 | self.__post_method = "POST" 26 | self.__payment_name = "payok" 27 | self.check_values() 28 | 29 | def check_values(self): 30 | if not self.__secretKey or not self.__apiKey or not self.__apiId or not self.__shopId: 31 | raise ValueError('No SecretKey, ApiKey, ShopID or ApiID specified') 32 | 33 | async def get_balance(self) -> Balance: 34 | """Get your balance. 35 | 36 | Docs: https://payok.io/cabinet/documentation/doc_api_balance 37 | """ 38 | url = f"{self.__base_url}/balance" 39 | 40 | params = { 41 | "API_ID": self.__apiId, 42 | "API_KEY": self.__apiKey, 43 | } 44 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 45 | 46 | return Balance(**response) 47 | 48 | async def get_transactions(self, payment: Optional[int] = None, 49 | offset: Optional[int] = None) -> Union[Transaction, List[Transaction]]: 50 | """Get list of transactions. 51 | 52 | Docs: https://payok.io/cabinet/documentation/doc_api_transaction 53 | 54 | :param payment: Optional. Payment ID in your system. 55 | :param offset: Optional. Indentation, skipping the specified number of lines. 56 | """ 57 | url = f"{self.__base_url}/transaction" 58 | 59 | params = { 60 | "API_ID": self.__apiId, 61 | "API_KEY": self.__apiKey, 62 | "shop": self.__shopId, 63 | "payment": payment, 64 | "offset": offset, 65 | } 66 | self._delete_empty_fields(params) 67 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 68 | if payment: 69 | return Transaction(**response['1']) 70 | 71 | return [Transaction(**transaction) for transaction in response.values()] 72 | 73 | async def get_payouts(self, payout_id: Optional[int] = None, offset: Optional[int] = None): 74 | """Get list of payouts. 75 | 76 | Docs: https://payok.io/cabinet/documentation/doc_api_payout 77 | 78 | :param payout_id: Payment ID in the Payok system. 79 | :param offset: Indentation, skipping the specified number of lines. 80 | """ 81 | url = f"{self.__base_url}/payout" 82 | params = { 83 | "API_ID": self.__apiId, 84 | "API_KEY": self.__apiKey, 85 | "payout_id": payout_id, 86 | "offset": offset, 87 | } 88 | self._delete_empty_fields(params) 89 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 90 | 91 | if payout_id: 92 | return Payout(**response['1']) 93 | 94 | return [Payout(**payout) for payout in response.values()] 95 | 96 | async def create_payout( 97 | self, 98 | amount: float, 99 | method: str, 100 | reciever: str, 101 | commission_type: str, 102 | sbp_bank: Optional[str] = None, 103 | webhook_url: Optional[str] = None 104 | ) -> CreatePayout: 105 | """ 106 | Create payout. 107 | 108 | Docs: https://payok.io/cabinet/documentation/doc_api_payout_create 109 | 110 | :param amount: Payment amount. 111 | :param method: Special value of the payment method, list of values. 112 | :param reciever: Details of the payee. 113 | :param commission_type: The bank for the payment of SBP. 114 | :param sbp_bank: Type of commission calculation: balance - Commission from the balance sheet, payment - Commission from the payment. 115 | :param webhook_url: URL for sending a Webhook when the payment status changes. 116 | """ 117 | url = f"{self.__base_url}/payout_create" 118 | params = { 119 | "API_ID": self.__apiId, 120 | "API_KEY": self.__apiKey, 121 | "amount": amount, 122 | "method": method, 123 | "reciever": reciever, 124 | "commission_type": commission_type, 125 | "sbp_bank": sbp_bank, 126 | "webhook_url": webhook_url 127 | } 128 | self._delete_empty_fields(params) 129 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 130 | 131 | return CreatePayout(remain_balance=response['remain_balance'], payout=PayoutOnCreate(**response['data'])) 132 | 133 | 134 | async def create_pay( 135 | self, 136 | amount: float, 137 | payment: Union[int, str], 138 | currency: Optional[str] = "RUB", 139 | desc: Optional[str] = 'Description', 140 | email: Optional[str] = None, 141 | success_url: Optional[str] = None, 142 | method: Optional[str] = None, 143 | lang: Optional[str] = None, 144 | custom: Optional[str] = None 145 | ) -> str: 146 | """Create payform url. 147 | 148 | Docs: https://payok.io/cabinet/documentation/doc_payform.php 149 | 150 | :param payment: Order number, unique in your system, up to 16 characters. (a-z0-9-_) 151 | :param amount : Order amount. 152 | :param currency : ISO 4217 currency. Default is "RUB". 153 | :param desc : Product name or description. 154 | :param email : Email Buyer mail. Defaults to None. 155 | :param success_url: Link to redirect after payment. 156 | :param method: Payment method 157 | :param lang: Interface language. RU or EN 158 | :param custom: Parameter that you want to pass in the notification. 159 | """ 160 | 161 | params = { 162 | 'amount': amount, 163 | 'payment': payment, 164 | 'shop': self.__shopId, 165 | 'currency': currency, 166 | 'desc': desc, 167 | 'email': email, 168 | 'success_url': success_url, 169 | 'method': method, 170 | 'lang': lang, 171 | 'custom': custom 172 | } 173 | 174 | self._delete_empty_fields(params) 175 | 176 | sign_params = '|'.join(map( 177 | str, 178 | [amount, payment, self.__shopId, currency, desc, self.__secretKey] 179 | )).encode('utf-8') 180 | sign = hashlib.md5(sign_params).hexdigest() 181 | params['sign'] = sign 182 | 183 | url = f'{self.API_HOST}/pay?' + urlencode(params) 184 | return url 185 | -------------------------------------------------------------------------------- /AsyncPayments/payok/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import Optional, Union 3 | 4 | 5 | class Balance(BaseModel): 6 | balance: int 7 | ref_balance: Union[str, float, int] 8 | 9 | 10 | class Transaction(BaseModel): 11 | transaction: Union[str, int] 12 | email: str 13 | amount: Union[str, int] 14 | currency: str 15 | currency_amount: Union[str, int] 16 | comission_percent: Union[str, int] 17 | comission_fixed: str 18 | amount_profit: Union[str, int] 19 | method: Optional[str] = None 20 | payment_id: Union[int, str] 21 | description: str 22 | date: str 23 | pay_date: str 24 | transaction_status: Union[str, int] 25 | custom_fields: Optional[Union[str, int, dict]] = None 26 | webhook_status: Union[str, int] 27 | webhook_amount: Union[str, int] 28 | 29 | 30 | class Payout(BaseModel): 31 | payout: int 32 | method: str 33 | reciever: str 34 | type: str 35 | amount: int 36 | comission_percent: int 37 | comission_fixed: str 38 | amount_profit: int 39 | date_create: str 40 | date_pay: str 41 | status: int 42 | 43 | 44 | class PayoutOnCreate(BaseModel): 45 | payout_id: int 46 | method: str 47 | reciever: str 48 | amount: int 49 | comission_percent: int 50 | comission_fixed: str 51 | amount_profit: int 52 | date: str 53 | payout_status_code: int 54 | payout_status_text: str 55 | 56 | 57 | class CreatePayout(BaseModel): 58 | remain_balance: Union[str, int, float] 59 | payout: PayoutOnCreate 60 | -------------------------------------------------------------------------------- /AsyncPayments/requests.py: -------------------------------------------------------------------------------- 1 | import ssl 2 | import certifi 3 | from typing import Optional 4 | from aiohttp import ClientSession, TCPConnector 5 | from .exceptions.exceptions import BadRequest, RequestError 6 | 7 | 8 | class RequestsClient: 9 | 10 | def __init__(self) -> None: 11 | self._session: Optional[ClientSession] = None 12 | 13 | def _getsession(self) -> ClientSession: 14 | 15 | if isinstance(self._session, ClientSession) and not self._session.closed: 16 | return self._session 17 | 18 | ssl_context = ssl.create_default_context(cafile=certifi.where()) 19 | connector = TCPConnector(ssl=ssl_context) 20 | 21 | self._session = ClientSession(connector=connector) 22 | 23 | return self._session 24 | 25 | def _delete_empty_fields(self, params: dict) -> None: 26 | for key, value in params.copy().items(): 27 | if value is None: 28 | params.pop(key) 29 | 30 | async def _request(self, payment: str, method: str, url: str, **kwargs) -> dict: 31 | session = self._getsession() 32 | 33 | async with session.request(method, url, **kwargs) as response: 34 | await self._session.close() 35 | if response.status in [200, 201]: 36 | if payment in ["ruKassa"]: 37 | response = await response.json(content_type="text/html") 38 | elif payment in ['payok']: 39 | response = await response.json(content_type="text/plain") 40 | else: 41 | response = await response.json() 42 | else: 43 | try: 44 | return await self._checkexception(payment, await response.json()) 45 | except: 46 | raise RequestError( 47 | f"{payment}. Response status: {response.status}. Text: {await response.text()}" 48 | ) 49 | return response 50 | 51 | async def _checkexception(self, payment: str, response: dict) -> dict: 52 | if payment == "aaio": 53 | if response["type"] == "error": 54 | raise BadRequest("[AAIO] " + response["message"]) 55 | elif payment == "crystalPay": 56 | if response["error"]: 57 | raise BadRequest("[CrystalPay] " + response["errors"][0]) 58 | elif payment == "cryptoBot": 59 | if not response["ok"]: 60 | raise BadRequest("[CryptoBot] " + response["error"]["name"]) 61 | elif payment == "lolz": 62 | if response.get("error"): 63 | raise BadRequest("[Lolzteam Market] " + response["error_description"]) 64 | if response.get("errors"): 65 | raise BadRequest("[Lolzteam Market] " + response["errors"][0]) 66 | elif payment == "ruKassa": 67 | if response.get("error"): 68 | raise BadRequest("[RuKassa] " + response["message"]) 69 | elif payment == "freeKassa": 70 | if response["type"] == "error" and not response.get("description"): 71 | raise BadRequest("[FreeKassa] " + response["message"]) 72 | elif payment == "cryptomus": 73 | if response.get('state') != 0: 74 | if response.get("errors"): 75 | raise BadRequest("[Cryptomus] " + str(response.get("errors"))) 76 | else: 77 | raise BadRequest("[Cryptomus] " + str(response.get("message"))) 78 | else: 79 | raise BadRequest("[Cryptomus] " + response.get("message")) 80 | elif payment == "xrocket": 81 | if not response.get("success"): 82 | text = f"[XRocket] {response.get('message')}" 83 | if response.get("errors"): 84 | text += ": \n" 85 | for error in response.get("errors"): 86 | text += f"Property: {error['property']} \nError: {error['error']}" 87 | raise BadRequest(text) 88 | else: 89 | raise BadRequest(f"[XRocket] Status code: {response.get('statusCode')}. Message: " + response.get("message")) 90 | else: 91 | # payok 92 | if response.get("status") and response.pop("status") == "error": 93 | raise BadRequest("[PayOK] " + response.get("text", response.get("error_text")) + ". Error code: " + response['error_code']) 94 | 95 | return response 96 | -------------------------------------------------------------------------------- /AsyncPayments/ruKassa/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import AsyncRuKassa -------------------------------------------------------------------------------- /AsyncPayments/ruKassa/api.py: -------------------------------------------------------------------------------- 1 | from ..requests import RequestsClient 2 | from typing import Optional, Union 3 | from .models import Balance, CreatePayment, Payment, CreateWithdrawRequest, CancelWithdrawRequest, WithdrawRequest, RevokePayment 4 | import time 5 | import secrets 6 | import random 7 | 8 | 9 | class AsyncRuKassa(RequestsClient): 10 | API_HOST: str = "https://ruks.pro" 11 | 12 | def __init__(self, api_token: str, shop_id: int, email: str, password: str) -> None: 13 | """ 14 | Initialize RuKassa API client 15 | :param api_token: Your RuKassa API-Token 16 | :param shop_id: Your RuKassa ShopID 17 | :param email: Your Email, which you pointed to RuKassa 18 | :param password: Your Password, which you pointed to RuKassa 19 | """ 20 | super().__init__() 21 | self.__token = api_token 22 | self.__shop_id = shop_id 23 | self.__email = email 24 | self.__password = password 25 | self.__base_url = "https://lk.rukassa.pro/api/v1" 26 | self.__post_method = "POST" 27 | self.__payment_name = "ruKassa" 28 | self.check_values() 29 | 30 | def check_values(self): 31 | if not self.__token or not self.__shop_id or not self.__email or not self.__password: 32 | raise ValueError('No Api-Token, ShopID, Email or Password specified') 33 | 34 | async def get_balance(self) -> Balance: 35 | """Get User Balance 36 | 37 | :return: Balance Object""" 38 | 39 | url = f'{self.__base_url}/getBalance' 40 | 41 | params = { 42 | "email": self.__email, 43 | "password": self.__password, 44 | } 45 | 46 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 47 | 48 | return Balance(**response) 49 | 50 | def __get_random_string(self): 51 | return f'{time.time()}_{secrets.token_hex(random.randint(5, 10))}' 52 | 53 | async def create_payment(self, amount: Union[int, float], currency: Optional[str] = "RUB", 54 | method: Optional[str] = None, data: Optional[str] = None, 55 | orderId: Optional[int] = None, userCode: Optional[str] = None) -> CreatePayment: 56 | """Create a payment 57 | 58 | :param amount: Amount of payment. 59 | :param currency: Optional. In what currency are you specifying the amount parameter? Default RUB. Currencies: RUB, USD 60 | :param method: Optional. Payment method, if you want payment to be made through a specific method. Methods: card, card_byn, card_kzt, card_uah, card_uzs, qiwi, yandexmoney, payeer, crypta, sbp, 61 | :param data: Optional. String sent to the server along with a notification of a successful payment. 62 | :param orderId: Optional. A unique payment number in your system. If not specified, a random string will be generated. 63 | :param userCode: Optional. For H2H, Anti-Fraud is required. Client ID (you can use the user's IP address or Telegram ID). 64 | 65 | :return: CreatePayment object 66 | """ 67 | 68 | url = f'{self.__base_url}/create' 69 | 70 | if not orderId: 71 | orderId = self.__get_random_string() 72 | 73 | params = { 74 | "shop_id": self.__shop_id, 75 | "order_id": orderId, 76 | "amount": amount, 77 | "token": self.__token, 78 | "data": data, 79 | "method": method, 80 | "currency": currency, 81 | "user_code": userCode, 82 | } 83 | 84 | for key, value in params.copy().items(): 85 | if value is None: 86 | params.pop(key) 87 | 88 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 89 | 90 | return CreatePayment(**response) 91 | 92 | async def revoke_payment(self, payment_id: int) -> RevokePayment: 93 | """ 94 | Revoke payment 95 | 96 | :param payment_id: Payment ID in our system. 97 | :return: RevokePayment object 98 | """ 99 | url = f"{self.__base_url}/revoke" 100 | params = { 101 | "id": payment_id, 102 | "shop_id": self.__shop_id, 103 | "token": self.__token, 104 | } 105 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 106 | return RevokePayment(**response) 107 | 108 | async def get_info_payment(self, payment_id: int) -> Payment: 109 | """ 110 | Get payment information 111 | 112 | :param payment_id: Transaction (entry) number in our system. 113 | 114 | :return: Payment object 115 | """ 116 | 117 | url = f"{self.__base_url}/getPayInfo" 118 | 119 | params = { 120 | "id": payment_id, 121 | "shop_id": self.__shop_id, 122 | "token": self.__token, 123 | } 124 | 125 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 126 | 127 | return Payment(**response) 128 | 129 | async def create_withdraw(self, way: str, wallet: str, amount: Union[float, int], orderId: str = None, 130 | check_from: Optional[str] = "BASE_RUB", who_fee: Optional[int] = 0, 131 | bank: Optional[int] = None) -> CreateWithdrawRequest: 132 | """ 133 | Create withdraw request 134 | 135 | :param way: Payment system for withdrawal. Systems: CARD, QIWI, YOOMONEY, USDT, SBP. 136 | :param wallet: The number of the wallet or card where the funds will be sent. 137 | :param amount: Amount to withdraw. 138 | :param orderId: ID in the merchant system. 139 | :param check_from: Account for debiting funds. Default: BASE_RUB. (BASE_RUB, BASE_USD). 140 | :param who_fee: Where to write off the commission. Default: 0. (0 - from account, 1 - from balance). 141 | :param bank: Only for SBP. Bank number. 142 | 143 | :return: CreateWithdrawRequest object 144 | """ 145 | 146 | url = f"{self.__base_url}/createWithdraw" 147 | 148 | params = { 149 | "email": self.__email, 150 | "password": self.__password, 151 | "way": way, 152 | "wallet": wallet, 153 | "amount": amount, 154 | "order_id": orderId, 155 | "from": check_from, 156 | "who_fee": who_fee, 157 | "bank": bank, 158 | } 159 | 160 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 161 | 162 | return CreateWithdrawRequest(**response) 163 | 164 | async def cancel_withdraw(self, payment_id: int) -> CancelWithdrawRequest: 165 | """ 166 | Cancel withdraw request 167 | 168 | :param payment_id: Payment ID in our system. 169 | 170 | :return: CancelWithdrawRequest object 171 | """ 172 | 173 | url = f"{self.__base_url}/cancelWithdraw" 174 | 175 | params = { 176 | "email": self.__email, 177 | "password": self.__password, 178 | "id": payment_id, 179 | } 180 | 181 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 182 | 183 | return CancelWithdrawRequest(**response) 184 | 185 | async def get_info_withdraw(self, payment_id: int) -> WithdrawRequest: 186 | """ 187 | Get info about withdraw request 188 | 189 | :param payment_id: The number of the operation (withdrawal) in our system. 190 | 191 | :return: WithdrawRequest object 192 | """ 193 | 194 | url = f"{self.__base_url}/getWithdrawInfo" 195 | 196 | params = { 197 | "token": self.__token, 198 | "shop_id": self.__shop_id, 199 | "id": payment_id, 200 | } 201 | 202 | response = await self._request(self.__payment_name, self.__post_method, url, data=params) 203 | 204 | return WithdrawRequest(**response) 205 | -------------------------------------------------------------------------------- /AsyncPayments/ruKassa/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import Union, Optional 3 | 4 | 5 | class Balance(BaseModel): 6 | balance_rub: float 7 | balance_usd: float 8 | 9 | 10 | class CreatePayment(BaseModel): 11 | id: int 12 | hash: str 13 | url: str 14 | 15 | 16 | class Payment(BaseModel): 17 | id: int 18 | order_id: Union[int, str] 19 | in_amount: Optional[float] = None 20 | amount: float 21 | currency: str 22 | status: str 23 | data: str 24 | 25 | 26 | class RevokePayment(BaseModel): 27 | id: int 28 | 29 | 30 | class CreateWithdrawRequest(BaseModel): 31 | id: int 32 | status: str 33 | 34 | 35 | class CancelWithdrawRequest(BaseModel): 36 | id: int 37 | status: str 38 | 39 | 40 | class WithdrawRequest(BaseModel): 41 | id: int 42 | order_id: Union[int, str] 43 | amount: float 44 | fee: Optional[float] = None 45 | way: str 46 | who_fee: str 47 | status: str 48 | -------------------------------------------------------------------------------- /AsyncPayments/xrocket/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import AsyncXRocket -------------------------------------------------------------------------------- /AsyncPayments/xrocket/api.py: -------------------------------------------------------------------------------- 1 | from ..requests import RequestsClient 2 | from typing import Optional, List 3 | from .models import AppInfo, Transfer, Withdrawal, WithdrawalFees, MultiCheque, MultiChequesList, Invoice, InvoicesList, Currency, \ 4 | Subscription, SubscriptionsList, SubscriptionCheck, Subscriptions 5 | from urllib.parse import urlencode 6 | 7 | 8 | class AsyncXRocket(RequestsClient): 9 | API_HOST: str = "https://t.me/tonRocketBot" 10 | 11 | def __init__(self, apiKey: str) -> None: 12 | """ 13 | Initialize XRocket API client 14 | :param apiKey: Your API key 15 | """ 16 | super().__init__() 17 | self.__api_key = apiKey 18 | self.__headers = { 19 | "Content-Type": "application/json", 20 | "Rocket-Pay-Key": self.__api_key, 21 | } 22 | self.__base_url = "https://pay.xrocket.tg" 23 | self.__post_method = "POST" 24 | self.__get_method = "GET" 25 | self.__put_method = "PUT" 26 | self.__delete_method = "DELETE" 27 | self.__payment_name = "xrocket" 28 | self.check_values() 29 | 30 | def check_values(self): 31 | if not self.__api_key: 32 | raise ValueError('No API key specified') 33 | 34 | async def get_app_info(self) -> AppInfo: 35 | """Returns information about your application. 36 | 37 | Docs: https://pay.xrocket.tg/api/#/app/AppsController_getAppInfo""" 38 | url = f"{self.__base_url}/app/info" 39 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 40 | return AppInfo(**response['data']) 41 | 42 | async def transfer(self, tgUserId: int, currency: str, amount: float, transferId: str, description: Optional[str] = "") -> Transfer: 43 | """Make transfer of funds to another user. 44 | 45 | :param tgUserId: Telegram user ID. If we dont have this user in DB, we will fail transaction with error: 400 - User not found. 46 | :param currency: Currency of transfer, info with function get_available_currencies(). 47 | :param amount: Transfer amount. 9 decimal places, others cut off. 48 | :param transferId: Unique transfer ID in your system to prevent double spends. 49 | :description: Transfer description. 50 | 51 | Docs: https://pay.xrocket.tg/api/#/app/AppsController_transfer""" 52 | url = f"{self.__base_url}/app/transfer" 53 | params = { 54 | "tgUserId": tgUserId, 55 | "currency": currency, 56 | "amount": amount, 57 | "transferId": transferId, 58 | "description": description, 59 | } 60 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 61 | return Transfer(**response['data']) 62 | 63 | async def withdrawal(self, network: str, address: str, currency: str, amount: float, withdrawalId: str, comment: Optional[str] = "") -> Withdrawal: 64 | """Make withdrawal of funds to external wallet. 65 | 66 | :param network: Network code. 67 | :param address: Withdrawal address. 68 | :param currency: Currency code. 69 | :param amount: Withdrawal amount. 9 decimal places, others cut off. 70 | :param withdrawalId: Unique withdrawal ID in your system to prevent double spends. 71 | :param comment: Withdrawal comment. 72 | 73 | Docs: https://pay.xrocket.tg/api/#/app/AppsController_withdrawal""" 74 | url = f"{self.__base_url}/app/withdrawal" 75 | params = { 76 | "network": network, 77 | "address": address, 78 | "currency": currency, 79 | "amount": amount, 80 | "withdrawalId": withdrawalId, 81 | "comment": comment, 82 | } 83 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 84 | return Withdrawal(**response['data']) 85 | 86 | async def withdrawal_status(self, withdrawalId: str) -> Withdrawal: 87 | """Returns withdrawal status. 88 | 89 | Docs: https://pay.xrocket.tg/api/#/app/AppsController_getWithdrawalStatus""" 90 | url = f"{self.__base_url}/app/withdrawal/status/{withdrawalId}" 91 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 92 | return Withdrawal(**response['data']) 93 | 94 | async def withdrawal_fees(self, currency: Optional[str] = None) -> List[WithdrawalFees]: 95 | """Returns withdrawal fees. 96 | 97 | Docs: https://pay.xrocket.tg/api/#/app/AppsController_getWithdrawalFees""" 98 | url = f"{self.__base_url}/app/withdrawal/fees" 99 | params = { 100 | "currency": currency, 101 | } 102 | self._delete_empty_fields(params) 103 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers, json=params) 104 | return [WithdrawalFees(**withdrawalFee) for withdrawalFee in response['data']] 105 | 106 | async def create_multi_cheque(self, currency: str, chequePerUser: float, usersNumber: int, refProgram: int, password: Optional[str] = None, 107 | description: Optional[str] = None, sendNotifications: Optional[bool] = True, enableCaptcha: Optional[bool] = True, 108 | telegramResourcesIds: Optional[List[str]] = [], forPremium: Optional[bool] = False, linkedWallet: Optional[bool] = False, 109 | disabledLanguages: Optional[List[str]] = [], enabledCountries: Optional[List[str]] = []) -> MultiCheque: 110 | """Create multi-cheque. 111 | 112 | :param currency: Currency of transfer, info with function get_available_currencies(). 113 | :param chequePerUser: Cheque amount for one user. 9 decimal places, others cut off. 114 | :param usersNumber: Number of users to save multicheque. 0 decimal places. 115 | :param refProgram: Referral program percentage (%). 0 decimal places. 116 | :param password: Password for cheque. 117 | :param description: Description for cheque. 118 | :param sendNotifications: Send notifications about activations. 119 | :param enableCaptcha: Enable captcha. 120 | :param telegramResourcesIds: IDs of telegram resources (groups, channels, private groups). 121 | :param forPremium: Only users with Telegram Premium can activate this cheque. 122 | :param linkedWallet: Only users with linked wallet can activate this cheque. 123 | :param disabledLanguages: Disable languages. 124 | :param enabledCountries: Enabled countries (AsyncPayments.xrocket.models.CountriesName). 125 | 126 | Docs: https://pay.xrocket.tg/api/#/multi-cheque/ChequesController_createCheque""" 127 | url = f"{self.__base_url}/multi-cheque" 128 | params = { 129 | "currency": currency, 130 | "chequePerUser": chequePerUser, 131 | "usersNumber": usersNumber, 132 | "refProgram": refProgram, 133 | "password": password, 134 | "description": description, 135 | "sendNotifications": sendNotifications, 136 | "enableCaptcha": enableCaptcha, 137 | "telegramResourcesIds": telegramResourcesIds, 138 | "forPremium": forPremium, 139 | "linkedWallet": linkedWallet, 140 | "disabledLanguages": disabledLanguages, 141 | "enabledCountries": enabledCountries, 142 | } 143 | self._delete_empty_fields(params) 144 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 145 | return MultiCheque(**response['data']) 146 | 147 | async def multi_cheques_list(self, limit: Optional[int] = 100, offset: Optional[int] = 0) -> MultiChequesList: 148 | """Get list of multi-cheques. 149 | 150 | :param limit: Limit of cheques. 151 | :param offset: Offset. 152 | 153 | Docs: https://pay.xrocket.tg/api/#/multi-cheque/ChequesController_getCheques""" 154 | params = { 155 | "limit": limit, 156 | "offset": offset, 157 | } 158 | url = f"{self.__base_url}/multi-cheque?{urlencode(params)}" 159 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 160 | return MultiChequesList(**response['data']) 161 | 162 | async def get_multi_cheque_info(self, cheque_id: int) -> MultiCheque: 163 | """Get multi-cheque info. 164 | 165 | :param cheque_id: ID of cheque. 166 | 167 | Docs: https://pay.xrocket.tg/api/#/multi-cheque/ChequesController_getCheque""" 168 | url = f"{self.__base_url}/multi-cheque/{cheque_id}" 169 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 170 | return MultiCheque(**response['data']) 171 | 172 | async def edit_multi_cheque(self, cheque_id: int, password: Optional[str] = None, description: Optional[str] = None, 173 | sendNotifications: Optional[bool] = None, enableCaptcha: Optional[bool] = None, 174 | telegramResourcesIds: Optional[List[str]] = None, forPremium: Optional[bool] = None, 175 | linkedWallet: Optional[bool] = None, disabledLanguages: Optional[List[str]] = None, 176 | enabledCountries: Optional[List[str]] = None) -> MultiCheque: 177 | """Edit multi-cheque. 178 | 179 | :param cheque_id: ID of cheque. 180 | :param password: Password for cheque. 181 | :param description: Description for cheque. 182 | :param sendNotifications: Send notifications about activations. 183 | :param enableCaptcha: Enable captcha. 184 | :param telegramResourcesIds: IDs of telegram resources (groups, channels, private groups). 185 | :param forPremium: Only users with Telegram Premium can activate this cheque. 186 | :param linkedWallet: Only users with linked wallet can activate this cheque. 187 | :param disabledLanguages: Disable languages. 188 | :param enabledCountries: Enabled countries (AsyncPayments.xrocket.models.CountriesName). 189 | 190 | 191 | Docs: https://pay.xrocket.tg/api/#/multi-cheque/ChequesController_editCheque""" 192 | params = { 193 | "password": password, 194 | "description": description, 195 | "sendNotifications": sendNotifications, 196 | "enableCaptcha": enableCaptcha, 197 | "telegramResourcesIds": telegramResourcesIds, 198 | "forPremium": forPremium, 199 | "linkedWallet": linkedWallet, 200 | "disabledLanguages": disabledLanguages, 201 | "enabledCountries": enabledCountries, 202 | } 203 | self._delete_empty_fields(params) 204 | url = f"{self.__base_url}/multi-cheque/{cheque_id}" 205 | response = await self._request(self.__payment_name, self.__put_method, url, headers=self.__headers, json=params) 206 | return MultiCheque(**response['data']) 207 | 208 | async def delete_multi_cheque(self, cheque_id: int) -> bool: 209 | """Delete multi-cheque. 210 | 211 | :param cheque_id: ID of cheque. 212 | 213 | Docs: https://pay.xrocket.tg/api/#/multi-cheque/ChequesController_deleteCheque""" 214 | url = f"{self.__base_url}/multi-cheque/{cheque_id}" 215 | response = await self._request(self.__payment_name, self.__delete_method, url, headers=self.__headers) 216 | return True if response['success'] else False 217 | 218 | async def create_invoice(self, numPayments: int, currency: str, amount: Optional[float] = None, minPayment: Optional[int] = None, 219 | description: Optional[str] = None, hiddenMessage: Optional[str] = None, commentsEnabled: Optional[bool] = None, 220 | callbackUrl: Optional[str] = None, payload: Optional[str] = None, expiredIn: Optional[int] = None) -> Invoice: 221 | """Create invoice. 222 | 223 | :param numPayments: Num payments for invoice. 224 | :param currency: Currency of transfer, info with function get_available_currencies(). 225 | :param amount: Invoice amount. 9 decimal places, others cut off. 226 | :param minPayment: Min payment only for multi invoice if invoice amount is None. 227 | :param description: Description for invoice. 228 | :param hiddenMessage: Hidden message after invoice is paid. 229 | :param commentsEnabled: Allow comments. 230 | :param callbackUrl: Url for Return button after invoice is paid. 231 | :param payload: Any data. Invisible to user, will be returned in callback. 232 | :param expiredIn: Invoice expire time in seconds, max 1 day, 0 - None expired. 233 | 234 | Docs: https://pay.xrocket.tg/api/#/tg-invoices/InvoicesController_createInvoice""" 235 | params = { 236 | "numPayments": numPayments, 237 | "currency": currency, 238 | "amount": amount, 239 | "minPayment": minPayment, 240 | "description": description, 241 | "hiddenMessage": hiddenMessage, 242 | "commentsEnabled": commentsEnabled, 243 | "callbackUrl": callbackUrl, 244 | "payload": payload, 245 | "expiredIn": expiredIn, 246 | } 247 | self._delete_empty_fields(params) 248 | url = f"{self.__base_url}/tg-invoices" 249 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 250 | return Invoice(**response['data']) 251 | 252 | async def get_list_invoices(self, limit: Optional[int] = 100, offset: Optional[int] = 0) -> InvoicesList: 253 | """Get list of invoices. 254 | 255 | :param limit: Limit of invoices. 256 | :param offset: Offset. 257 | 258 | Docs: https://pay.xrocket.tg/api/#/tg-invoices/InvoicesController_getInvoices""" 259 | params = { 260 | "limit": limit, 261 | "offset": offset, 262 | } 263 | url = f"{self.__base_url}/tg-invoices?{urlencode(params)}" 264 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 265 | return InvoicesList(**response['data']) 266 | 267 | async def get_invoice_info(self, invoice_id: str) -> Invoice: 268 | """Get invoice info. 269 | 270 | :param invoice_id: ID of invoice. 271 | 272 | Docs: https://pay.xrocket.tg/api/#/tg-invoices/InvoicesController_getInvoice""" 273 | url = f"{self.__base_url}/tg-invoices/{invoice_id}" 274 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 275 | return Invoice(**response['data']) 276 | 277 | async def delete_invoice(self, invoice_id: str) -> bool: 278 | """Delete invoice. 279 | 280 | :param invoice_id: ID of invoice. 281 | 282 | Docs: https://pay.xrocket.tg/api/#/tg-invoices/InvoicesController_deleteInvoice""" 283 | url = f"{self.__base_url}/tg-invoices/{invoice_id}" 284 | response = await self._request(self.__payment_name, self.__delete_method, url, headers=self.__headers) 285 | return True if response['success'] else False 286 | 287 | async def get_challenge(self, challenge_id: str, user_id: str) -> str: 288 | """Get challenge amount by user id. 289 | 290 | :param challenge_id: ID of the challenge. 291 | :param user_id: Telegram ID of the user. 292 | 293 | Docs: https://pay.xrocket.tg/api/#/challenges/ChallengesController_getTradeAmount 294 | 295 | :return: Amount in USD.""" 296 | url = f"{self.__base_url}/challenges/{challenge_id}/users/{user_id}" 297 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 298 | return response['data']['amountUsd'] 299 | 300 | async def get_available_currencies(self) -> List[Currency]: 301 | """Returns available currencies. 302 | 303 | Docs: https://pay.xrocket.tg/api/#/currencies/CurrenciesController_getCoins""" 304 | url = f"{self.__base_url}/currencies/available" 305 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 306 | return [Currency(**currency) for currency in response['data']['results']] 307 | 308 | async def create_subscription(self, interval: str, amount: float, status: str, referralPercent: int, currency: str, name: Optional[str] = None, 309 | description: Optional[str] = None, tgResource: Optional[str] = None, returnUrl: Optional[str] = None) -> Subscription: 310 | """Create subscription. 311 | 312 | :param interval: Interval for subscription (AsyncPayments.xrocket.models.SubscriptionsIntervals). 313 | :param amount: Cost subscription for current interval in currency. 314 | :param status: Status for subscription (AsyncPayments.xrocket.models.SubscriptionsStatuses). 315 | :param referralPercent: Subscription referral percent. 316 | :param currency: Subscription currency. 317 | :param name: Subscription name, view in bot. 318 | :param description: Subscription description, view in bot. 319 | :param tgResource: Subscription TG resource. 320 | :param returlUrl: Return link after payment. 321 | 322 | Docs: https://pay.xrocket.tg/api/#/subscriptions/SubscriptionsController_createSubscription""" 323 | params = { 324 | "name": name, 325 | "description": description, 326 | "currency": currency, 327 | "interval": [ 328 | { 329 | "interval": interval, 330 | "amount": amount, 331 | "status": status 332 | } 333 | ], 334 | "tgResource": tgResource, 335 | "referralPercent": referralPercent, 336 | "returnUrl": returnUrl 337 | } 338 | self._delete_empty_fields(params) 339 | url = f"{self.__base_url}/subscriptions" 340 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 341 | return Subscription(**response['data']) 342 | 343 | async def get_list_subscriptions(self, limit: Optional[int] = 100, offset: Optional[int] = 0) -> SubscriptionsList: 344 | """Get list of subscription. 345 | 346 | :param limit: Limit of subscriptions. 347 | :param offset: Offset. 348 | 349 | Docs: https://pay.xrocket.tg/api/#/subscriptions/SubscriptionsController_getSubscriptions""" 350 | params = { 351 | "limit": limit, 352 | "offset": offset, 353 | } 354 | url = f"{self.__base_url}/subscriptions?{urlencode(params)}" 355 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 356 | return SubscriptionsList(**response['data']) 357 | 358 | async def get_subscription_info(self, subscription_id: int) -> Subscription: 359 | """Get subscription info. 360 | 361 | :param subscription_id: ID of the subscription. 362 | 363 | Docs: https://pay.xrocket.tg/api/#/subscriptions/SubscriptionsController_getSubscription""" 364 | url = f"{self.__base_url}/subscriptions/{subscription_id}" 365 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 366 | return Subscription(**response['data']) 367 | 368 | async def delete_subscription(self, subscription_id: int) -> bool: 369 | """Delete subscription. 370 | 371 | :param subscription_id: ID of the subscription. 372 | 373 | Docs: https://pay.xrocket.tg/api/#/subscriptions/SubscriptionsController_deleteSubscription""" 374 | url = f"{self.__base_url}/subscriptions/{subscription_id}" 375 | response = await self._request(self.__payment_name, self.__delete_method, url, headers=self.__headers) 376 | return True if response['success'] else False 377 | 378 | async def check_subscription(self, subscription_id: int, user_id: int) -> SubscriptionCheck: 379 | """Delete subscription. 380 | 381 | :param subscription_id: ID of the subscription. 382 | :param user_id: ID of the user. 383 | 384 | Docs: https://pay.xrocket.tg/api/#/subscriptions/SubscriptionsController_checkSubscription""" 385 | params = { 386 | "userId": user_id, 387 | } 388 | url = f"{self.__base_url}/subscriptions/check/{subscription_id}" 389 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers, json=params) 390 | return SubscriptionCheck(**response['data']) 391 | 392 | async def get_subscription_interval_info(self, subscription_id: int, interval_code: str) -> Subscriptions.Interval: 393 | """Get subscription interval info. 394 | 395 | :param subscription_id: ID of the subscription. 396 | :param interval_code: Code of the interval. 397 | 398 | Docs: https://pay.xrocket.tg/api/#/subscriptions/SubscriptionsController_getSubscriptionInterval""" 399 | url = f"{self.__base_url}/subscriptions/{subscription_id}/interval/{interval_code}" 400 | response = await self._request(self.__payment_name, self.__get_method, url, headers=self.__headers) 401 | return Subscriptions.Interval(**response['data']) 402 | 403 | async def edit_subscription_interval(self, subscription_id: int, interval_code: str, status: str) -> Subscriptions.Interval: 404 | """Edit subscription interval. 405 | 406 | :param subscription_id: ID of the subscription. 407 | :param interval_code: Code of the interval. 408 | :param status: Status for subscription (AsyncPayments.xrocket.models.SubscriptionsStatuses). 409 | 410 | Docs: https://pay.xrocket.tg/api/#/subscriptions/SubscriptionsController_editSubscriptionInterval""" 411 | params = { 412 | "status": status 413 | } 414 | url = f"{self.__base_url}/subscriptions/{subscription_id}/interval/{interval_code}" 415 | response = await self._request(self.__payment_name, self.__put_method, url, headers=self.__headers, json=params) 416 | return Subscriptions.Interval(**response['data']) 417 | 418 | async def delete_subscription_interval(self, subscription_id: int, interval_code: str) -> Subscriptions.Interval: 419 | """Delete subscription interval. 420 | 421 | :param subscription_id: ID of the subscription. 422 | :param interval_code: Code of the interval. 423 | 424 | Docs: https://pay.xrocket.tg/api/#/subscriptions/SubscriptionsController_deleteSubscriptionInterval""" 425 | url = f"{self.__base_url}/subscriptions/{subscription_id}/interval/{interval_code}" 426 | response = await self._request(self.__payment_name, self.__delete_method, url, headers=self.__headers) 427 | return Subscriptions.Interval(**response['data']) 428 | 429 | async def create_subscription_interval(self, subscription_id: int, interval: str, amount: float, status: str) -> Subscriptions.Interval: 430 | """Create subscription interval. 431 | 432 | :param subscription_id: ID of the subscription. 433 | :param interval: Interval for subscription (AsyncPayments.xrocket.models.SubscriptionsIntervals). 434 | :param amount: Cost subscription for current interval in currency. 435 | :param status: Status for subscription (AsyncPayments.xrocket.models.SubscriptionsStatuses). 436 | 437 | Docs: https://pay.xrocket.tg/api/#/subscriptions/SubscriptionsController_creteSubscriptionInterval""" 438 | params = { 439 | "interval": interval, 440 | "amount": amount, 441 | "status": status, 442 | } 443 | url = f"{self.__base_url}/subscriptions/{subscription_id}" 444 | response = await self._request(self.__payment_name, self.__post_method, url, headers=self.__headers) 445 | return Subscriptions.Interval(**response['data']) -------------------------------------------------------------------------------- /AsyncPayments/xrocket/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | from typing import Optional, Union, List 3 | 4 | 5 | class Balance(BaseModel): 6 | currency: str 7 | balance: Union[int, float] 8 | 9 | 10 | class AppInfo(BaseModel): 11 | name: str 12 | feePercents: Union[int, float] 13 | balances: List[Balance] 14 | 15 | 16 | class Transfer(BaseModel): 17 | id: int 18 | tgUserId: int 19 | currency: str 20 | amount: Union[int, float] 21 | description: str 22 | 23 | 24 | class Withdrawal(BaseModel): 25 | network: str 26 | address: str 27 | currency: str 28 | amount: Union[int, float] 29 | withdrawalId: str 30 | status: str 31 | comment: str 32 | txHash: str 33 | txLink: str 34 | 35 | 36 | class FeeWithdraw(BaseModel): 37 | fee: Optional[float] = None 38 | currency: str 39 | 40 | 41 | class Fee(BaseModel): 42 | networkCode: str 43 | feeWithdraw: FeeWithdraw 44 | 45 | 46 | class WithdrawalFees(BaseModel): 47 | code: str 48 | minWithdraw: float 49 | fees: List[Fee] 50 | 51 | 52 | class MultiCheque(BaseModel): 53 | id: int 54 | currency: str 55 | total: int 56 | perUser: int 57 | users: int 58 | password: str 59 | description: str 60 | sendNotifications: bool 61 | captchaEnabled: bool 62 | refProgramPercents: int 63 | refRewardPerUser: float 64 | state: str 65 | link: str 66 | disabledLanguages: list 67 | enabledCountries: list 68 | forPremium: int 69 | forNewUsersOnly: int 70 | linkedWallet: int 71 | tgResources: Optional[list] = None 72 | activations: Optional[int] = None 73 | refRewards: Optional[int] = None 74 | 75 | 76 | class MultiChequesList(BaseModel): 77 | total: int 78 | limit: int 79 | offset: int 80 | results: List[MultiCheque] 81 | 82 | 83 | class InvoicePayment(BaseModel): 84 | userId: int 85 | paymentNum: int 86 | paymentAmount: int 87 | comment: str 88 | paid: str 89 | 90 | 91 | class Invoice(BaseModel): 92 | id: str 93 | amount: Union[float, int] 94 | minPayment: Optional[Union[float, int]] = None 95 | totalActivations: int 96 | activationsLeft: int 97 | description: Optional[str] = None 98 | hiddenMessage: Optional[str] = None 99 | payload: Optional[str] = None 100 | callbackUrl: Optional[str] = None 101 | commentsEnabled: Union[bool, int] 102 | currency: str 103 | created: Optional[str] = None 104 | paid: Optional[str] = None 105 | status: str 106 | expiredIn: int 107 | link: str 108 | payments: Optional[List[InvoicePayment]] = [] 109 | 110 | 111 | class InvoicesList(BaseModel): 112 | total: int 113 | limit: int 114 | offset: int 115 | results: List[Invoice] 116 | 117 | 118 | class Currency(BaseModel): 119 | currency: str 120 | name: str 121 | minTransfer: Union[float, int] 122 | minCheque: Union[float, int] 123 | minInvoice: Union[float, int] 124 | minWithdraw: Union[float, int] 125 | feeWithdraw: dict 126 | 127 | 128 | class Subscriptions: 129 | class Interval(BaseModel): 130 | interval: str 131 | amount: Union[float, int] 132 | status: str 133 | code: str 134 | 135 | class tgResource(BaseModel): 136 | id: int 137 | type_: str = Field(alias="type") 138 | resourceId: str 139 | name: str 140 | linkedChat: str 141 | 142 | 143 | class Subscription(BaseModel): 144 | id: int 145 | name: str 146 | description: str 147 | currency: str 148 | link: str 149 | interval: Subscriptions.Interval 150 | referralPercent: int 151 | returnUrl: str 152 | tgResource: Subscriptions.tgResource 153 | 154 | 155 | class SubscriptionsList(BaseModel): 156 | total: int 157 | limit: int 158 | offset: int 159 | results: List[Subscription] 160 | 161 | 162 | class SubscriptionCheck(BaseModel): 163 | subscriptionId: int 164 | subscriptionCode: str 165 | userId: int 166 | amount: Union[float, int] 167 | currency: str 168 | interval: str 169 | refFee: Union[float, int] 170 | isRefPay: bool 171 | totalAmount: Union[float, int] 172 | paymentStart: str 173 | paymentEnd: str 174 | autoRenewal: bool 175 | transactions: list 176 | 177 | 178 | class SubscriptionsStatutes: 179 | ACTIVE = "ACTIVE" 180 | ARCHIVE = "ARCHIVE" 181 | DELETED = "DELETED" 182 | 183 | 184 | class SubscriptionsIntervals: 185 | DAY = "DAY" 186 | WEEK = "WEEK" 187 | MONTH = "MONTH" 188 | YEAR = "YEAR" 189 | FOREVER = "FOREVER" 190 | 191 | 192 | class InvoiceStatutes: 193 | ACTIVE = "active" 194 | PAID = "paid" 195 | EXPIRED = "expired" 196 | 197 | 198 | class CountriesName: 199 | DZ: str = "DZ" 200 | AO: str = "AO" 201 | BJ: str = "BJ" 202 | BW: str = "BW" 203 | BF: str = "BF" 204 | BI: str = "BI" 205 | CV: str = "CV" 206 | CM: str = "CM" 207 | CF: str = "CF" 208 | TD: str = "TD" 209 | KM: str = "KM" 210 | CG: str = "CG" 211 | CD: str = "CD" 212 | DJ: str = "DJ" 213 | EG: str = "EG" 214 | GQ: str = "GQ" 215 | ER: str = "ER" 216 | SZ: str = "SZ" 217 | ET: str = "ET" 218 | GA: str = "GA" 219 | GM: str = "GM" 220 | GH: str = "GH" 221 | GN: str = "GN" 222 | GW: str = "GW" 223 | CI: str = "CI" 224 | KE: str = "KE" 225 | LS: str = "LS" 226 | LR: str = "LR" 227 | LY: str = "LY" 228 | MG: str = "MG" 229 | MW: str = "MW" 230 | ML: str = "ML" 231 | MR: str = "MR" 232 | MU: str = "MU" 233 | MA: str = "MA" 234 | MZ: str = "MZ" 235 | NA: str = "NA" 236 | NE: str = "NE" 237 | NG: str = "NG" 238 | RW: str = "RW" 239 | ST: str = "ST" 240 | SN: str = "SN" 241 | SC: str = "SC" 242 | SL: str = "SL" 243 | SO: str = "SO" 244 | ZA: str = "ZA" 245 | SS: str = "SS" 246 | SD: str = "SD" 247 | TZ: str = "TZ" 248 | TG: str = "TG" 249 | TN: str = "TN" 250 | UG: str = "UG" 251 | ZM: str = "ZM" 252 | ZW: str = "ZW" 253 | AF: str = "AF" 254 | AM: str = "AM" 255 | AZ: str = "AZ" 256 | BH: str = "BH" 257 | BD: str = "BD" 258 | BT: str = "BT" 259 | BN: str = "BN" 260 | MM: str = "MM" 261 | KH: str = "KH" 262 | CN: str = "CN" 263 | CY: str = "CY" 264 | GE: str = "GE" 265 | IN: str = "IN" 266 | ID: str = "ID" 267 | IR: str = "IR" 268 | IQ: str = "IQ" 269 | IL: str = "IL" 270 | JP: str = "JP" 271 | JO: str = "JO" 272 | KZ: str = "KZ" 273 | KW: str = "KW" 274 | KG: str = "KG" 275 | LA: str = "LA" 276 | LB: str = "LB" 277 | MY: str = "MY" 278 | MV: str = "MV" 279 | MN: str = "MN" 280 | NP: str = "NP" 281 | KP: str = "KP" 282 | KR: str = "KR" 283 | OM: str = "OM" 284 | PK: str = "PK" 285 | PS: str = "PS" 286 | PH: str = "PH" 287 | QA: str = "QA" 288 | SA: str = "SA" 289 | SG: str = "SG" 290 | LK: str = "LK" 291 | SY: str = "SY" 292 | TW: str = "TW" 293 | TJ: str = "TJ" 294 | TH: str = "TH" 295 | TR: str = "TR" 296 | TM: str = "TM" 297 | AE: str = "AE" 298 | UZ: str = "UZ" 299 | VN: str = "VN" 300 | YE: str = "YE" 301 | AL: str = "AL" 302 | AD: str = "AD" 303 | AT: str = "AT" 304 | BY: str = "BY" 305 | BE: str = "BE" 306 | BA: str = "BA" 307 | BG: str = "BG" 308 | HR: str = "HR" 309 | CZ: str = "CZ" 310 | DK: str = "DK" 311 | EE: str = "EE" 312 | FI: str = "FI" 313 | FR: str = "FR" 314 | DE: str = "DE" 315 | GR: str = "GR" 316 | HU: str = "HU" 317 | IS: str = "IS" 318 | IE: str = "IE" 319 | IT: str = "IT" 320 | XK: str = "XK" 321 | LV: str = "LV" 322 | LI: str = "LI" 323 | LT: str = "LT" 324 | LU: str = "LU" 325 | MT: str = "MT" 326 | MD: str = "MD" 327 | MC: str = "MC" 328 | ME: str = "ME" 329 | NL: str = "NL" 330 | MK: str = "MK" 331 | NO: str = "NO" 332 | PL: str = "PL" 333 | PT: str = "PT" 334 | RO: str = "RO" 335 | RU: str = "RU" 336 | SM: str = "SM" 337 | RS: str = "RS" 338 | SK: str = "SK" 339 | SI: str = "SI" 340 | ES: str = "ES" 341 | SE: str = "SE" 342 | CH: str = "CH" 343 | UA: str = "UA" 344 | GB: str = "GB" 345 | VA: str = "VA" 346 | AG: str = "AG" 347 | BS: str = "BS" 348 | BB: str = "BB" 349 | BZ: str = "BZ" 350 | CA: str = "CA" 351 | CR: str = "CR" 352 | CU: str = "CU" 353 | DM: str = "DM" 354 | DO: str = "DO" 355 | SV: str = "SV" 356 | GD: str = "GD" 357 | GT: str = "GT" 358 | HT: str = "HT" 359 | HN: str = "HN" 360 | JM: str = "JM" 361 | MX: str = "MX" 362 | NI: str = "NI" 363 | PA: str = "PA" 364 | KN: str = "KN" 365 | LC: str = "LC" 366 | VC: str = "VC" 367 | TT: str = "TT" 368 | US: str = "US" 369 | AR: str = "AR" 370 | BO: str = "BO" 371 | BR: str = "BR" 372 | CL: str = "CL" 373 | CO: str = "CO" 374 | EC: str = "EC" 375 | GY: str = "GY" 376 | PY: str = "PY" 377 | PE: str = "PE" 378 | SR: str = "SR" 379 | UY: str = "UY" 380 | VE: str = "VE" 381 | AU: str = "AU" 382 | FJ: str = "FJ" 383 | KI: str = "KI" 384 | MH: str = "MH" 385 | FM: str = "FM" 386 | NR: str = "NR" 387 | NZ: str = "NZ" 388 | PW: str = "PW" 389 | PG: str = "PG" 390 | WS: str = "WS" 391 | SB: str = "SB" 392 | TO: str = "TO" 393 | TV: str = "TV" 394 | VU: str = "VU" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 ToSa 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AsyncPayments 2 | ![PyPiAsyncPaymentsPackage](https://img.shields.io/badge/pypi-AsyncPayments-red) 3 | ![PyPiAsyncPaymentsPackageVersion](https://img.shields.io/pypi/v/AsyncPayments) 4 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/AsyncPayments?color=brightgreen) 5 | 6 | > Add payment acceptance to your projects. 7 | ## Installing 8 | pip install AsyncPayments 9 | ## Version 10 | v1.4.7 11 | ## Code example 12 | 13 | ```python 14 | import asyncio 15 | 16 | from AsyncPaymentsTest.ruKassa import AsyncRuKassa 17 | from AsyncPaymentsTest.lolz import AsyncLolzteamMarketPayment 18 | from AsyncPaymentsTest.aaio import AsyncAaio 19 | from AsyncPaymentsTest.cryptoBot import AsyncCryptoBot 20 | from AsyncPaymentsTest.crystalPay import AsyncCrystalPay 21 | from AsyncPaymentsTest.freeKassa import AsyncFreeKassa 22 | from AsyncPaymentsTest.payok import AsyncPayOK 23 | from AsyncPaymentsTest.cryptomus import AsyncCryptomus 24 | from AsyncPaymentsTest.xrocket import AsyncXRocket 25 | 26 | ruKassa = AsyncRuKassa(api_token="ApiToken", shop_id=1, email="Email", password="Password") 27 | lolz = AsyncLolzteamMarketPayment(token="Token") 28 | aaio = AsyncAaio(apikey="ApiKey", shopid="ShopID", secretkey="SecretKey") 29 | cryptoBot = AsyncCryptoBot(token="CryptoPayToken", is_testnet=False) 30 | crystalPay = AsyncCrystalPay(login="Login", secret="Secret", salt="Salt") 31 | freeKassa = AsyncFreeKassa(apiKey="ApiKey", shopId=1) 32 | payok = AsyncPayOK(apiKey="ApiKey", secretKey="SecretKey", apiId=1, shopId=1) 33 | cryptomus = AsyncCryptomus(payment_api_key="PaymentApiKey", merchant_id="MerchantID", payout_api_key="PayoutApiKey") 34 | xrocket = AsyncXRocket(apiKey="ApiKey") 35 | 36 | 37 | async def main(): 38 | balance_payok = await payok.get_balance() 39 | balance_freekassa = await freeKassa.get_balance() 40 | balance_rukassa = await ruKassa.get_balance() 41 | balance_lolz = await lolz.get_me() 42 | balance_aaio = await aaio.get_balance() 43 | balance_crypto_bot = await cryptoBot.get_balance() 44 | balance_crystal_pay = await crystalPay.get_balance_list() 45 | balance_cryptomus = await cryptomus.get_balance() 46 | balance_xrocket = await xrocket.get_app_info() 47 | 48 | print("PayOK:") 49 | print("Balance: ", balance_payok.balance) 50 | print("Referral balance: ", balance_payok.ref_balance) 51 | print('--------------') 52 | print("FreeKassa:") 53 | for balance in balance_freekassa: 54 | print(f"{balance.currency}: ", balance.value) 55 | print('--------------') 56 | print("RuKassa:") 57 | print("RUB: ", balance_rukassa.balance_rub) 58 | print("USD: ", balance_rukassa.balance_usd) 59 | print('--------------') 60 | print("Lolz:") 61 | print('ID: ', balance_lolz.user_id) 62 | print('Nickname: ', balance_lolz.username) 63 | print('Available: ', balance_lolz.balance) 64 | print('In hold: ', balance_lolz.hold) 65 | print('--------------') 66 | print("Aaio:") 67 | print('Available: ', balance_aaio.balance) 68 | print('In hold: ', balance_aaio.hold) 69 | print('Referral balance: ', balance_aaio.referral) 70 | print('--------------') 71 | print("CryptoBot:") 72 | for balance in balance_crypto_bot: 73 | print(f"Available {balance.currency_code}: ", balance.available, f" (In hold: {balance.onhold})") 74 | print('--------------') 75 | print("CrystalPay:") 76 | for currency, balance in balance_crystal_pay: 77 | print(f"Available {currency}: {balance.amount} {balance.currency}") 78 | print('--------------') 79 | print("Cryptomus:") 80 | print("Merchant:\n") 81 | for balance in balance_cryptomus.merchant: 82 | print( 83 | f"Available {balance.currency_code}: {balance.balance} {balance.currency_code} ({balance.balance_usd} USD)") 84 | print("\nUser:\n") 85 | for balance in balance_cryptomus.user: 86 | print( 87 | f"Available {balance.currency_code}: {balance.balance} {balance.currency_code} ({balance.balance_usd} USD)") 88 | print('--------------') 89 | print('XRocket:') 90 | for bal in balance.balances: 91 | print(f"Available {bal.currency}: {bal.balance} {bal.currency}") 92 | print('------------------------------------------') 93 | 94 | order_payok = await payok.create_pay(15, "orderId") 95 | order_freeKassa = await freeKassa.create_order(1, "example@gmail.com", "0.0.0.0", 150, "RUB") 96 | order_ruKassa = await ruKassa.create_payment(15) 97 | order_lolz = await lolz.create_invoice(15, "paymentId", "comment", "https://example.com", 1) 98 | order_aaio = await aaio.create_payment_url(15, "orderId") 99 | order_crypto_bot = await cryptoBot.create_invoice(15, currency_type="crypto", asset="USDT") 100 | order_crystal_pay = await crystalPay.create_payment(15) 101 | order_cryptomus = await cryptomus.create_payment("15", "RUB", "orderId") 102 | order_xrocket = await xrocket.create_invoice(1, "TONCOIN", 1) 103 | 104 | print("PayOK", order_payok) 105 | print("FreeKassa", order_freeKassa.location) 106 | print("RuKassa: ", order_ruKassa.url) 107 | print("Lolz: ":, order_lolz.url) 108 | print("Aaio: ", order_aaio) 109 | print("CryptoBot: ", order_crypto_bot.pay_url) 110 | print("CrystalPay: ", order_crystal_pay.url) 111 | print("Cryptomus: ", order_cryptomus.url) 112 | print("XRocket: ", order_xrocket.link) 113 | 114 | print('------------------------------------------') 115 | 116 | info_payok = await payok.get_transactions("orderId") 117 | info_freeKassa = await freeKassa.get_orders("orderId") 118 | info_ruKassa = await ruKassa.get_info_payment("orderId") 119 | info_lolz = await lolz.get_invoice(payment_id="paymentId") 120 | info_aaio = await aaio.get_order_info("orderId") 121 | info_crypto_bot = await cryptoBot.get_invoices( 122 | invoice_ids=["orderId"], count=1 123 | ) 124 | info_crystal_pay = await crystalPay.get_payment_info("orderId") 125 | info_cryptomus = await cryptomus.payment_info(order_id="orderId") 126 | info_xrocket = await xrocket.get_invoice_info('orderId') 127 | 128 | print("PayOK:") 129 | print("Amount: ", info_payok.amount) 130 | print("Status: ", info_payok.transaction_status) 131 | print('--------------') 132 | print("FreeKassa:") 133 | print("Amount: ", info_freeKassa.orders[0].amount) 134 | print("Status: ", info_freeKassa.orders[0].status) 135 | print('--------------') 136 | print('RuKassa:') 137 | print("Amount: ", info_ruKassa.amount) 138 | print("Status: ", info_ruKassa.status) 139 | print('--------------') 140 | print("Lolz:") 141 | print("Amount: ", info_lolz.amount) 142 | print("Status: ", info_lolz.status) 143 | print('--------------') 144 | print("Aaio:") 145 | print("Amount: ", info_aaio.amount) 146 | print("Status: ", info_aaio.status) 147 | print('--------------') 148 | print("CryptoBot:") 149 | print("Amount: ", info_crypto_bot.amount) 150 | print("Status: ", info_crypto_bot.status) 151 | print('--------------') 152 | print("CrystalPay:") 153 | print("Amount: ", info_crystal_pay.rub_amount) 154 | print("Status:", info_crystal_pay.state) 155 | print('--------------') 156 | print("Cryptomus:") 157 | print("Amount: ", info_cryptomus.amount) 158 | print("Status: ", info_cryptomus.payment_status) 159 | print('--------------') 160 | print("XRocket:") 161 | print("Amount": info_xrocket.amount) 162 | print("Status": info_xrocket.status) 163 | 164 | asyncio.run(main()) 165 | ``` 166 | ## Output 167 | ```Python 168 | PayOK: 169 | Balance: 0 170 | Referral balance: 0.00 171 | -------------- 172 | FreeKassa: 173 | RUB: 0.00 174 | USD: 0.00 175 | EUR: 0.00 176 | KZT: 0.00 177 | UAH: 0.00 178 | -------------- 179 | RuKassa: 180 | RUB: 34.0 181 | USD: 234.1 182 | -------------- 183 | Lolz: 184 | ID: 4810752 185 | Nickname: ToSa 186 | Available: 5233.0 187 | In hold: 234.0 188 | -------------- 189 | Aaio: 190 | Available: 1235.0 191 | In hold: 0.0 192 | Referral balance: 0.0 193 | -------------- 194 | CryptoBot: 195 | Available USDT: 15.0 (In hold: 0.0) 196 | Available TON: 0.0 (In hold: 0.0) 197 | Available BTC: 0.00000023 (In hold: 0.0) 198 | Available LTC: 0.0 (In hold: 0.0) 199 | Available ETH: 0.0 (In hold: 0.0) 200 | Available BNB: 0.0 (In hold: 0.0) 201 | Available TRX: 0.0 (In hold: 0.0) 202 | Available USDC: 0.0 (In hold: 0.0) 203 | -------------- 204 | CrystalPay: 205 | Available BITCOIN: 0 BTC 206 | Available BITCOINCASH: 0 BCH 207 | Available BNBCRYPTOBOT: 0 BNB 208 | Available BNBSMARTCHAIN: 0 BNB 209 | Available BTCCRYPTOBOT: 0 BTC 210 | Available CARDRUBP2P: 0 RUB 211 | Available DASH: 0 DASH 212 | Available DOGECOIN: 0 DOGE 213 | Available ETHCRYPTOBOT: 0 ETH 214 | Available ETHEREUM: 0 ETH 215 | Available LITECOIN: 0 LTC 216 | Available LTCCRYPTOBOT: 0 LTC 217 | Available LZTMARKET: 0 RUB 218 | Available POLYGON: 0 MATIC 219 | Available SBERPAYP2P: 0 RUB 220 | Available SBPP2P: 0 RUB 221 | Available TONCOIN: 0 TON 222 | Available TONCRYPTOBOT: 0 TON 223 | Available TRON: 0 TRX 224 | Available USDCTRC: 0 USDC 225 | Available USDTCRYPTOBOT: 0 USDT 226 | Available USDTTRC: 0 USDT 227 | -------------- 228 | Cryptomus: 229 | Merchant: 230 | 231 | Available VERSE: 0.00000000 VERSE (0.00000000 USD) 232 | Available DAI: 0.00000000 DAI (0.00000000 USD) 233 | Available ETH: 0.00000000 ETH (0.00000000 USD) 234 | Available BCH: 0.00000000 BCH (0.00000000 USD) 235 | Available DASH: 0.00000000 DASH (0.00000000 USD) 236 | Available BNB: 0.00000000 BNB (0.00000000 USD) 237 | Available XMR: 0.00000000 XMR (0.00000000 USD) 238 | Available SOL: 0.00000000 SOL (0.00000000 USD) 239 | Available DOGE: 0.00000000 DOGE (0.00000000 USD) 240 | Available USDC: 0.00980000 USDC (0.00980031 USD) 241 | Available CGPT: 0.00000000 CGPT (0.00000000 USD) 242 | Available USDT: 0.00315576 USDT (0.00315333 USD) 243 | Available TON: 0.00000000 TON (0.00000000 USD) 244 | Available BUSD: 0.00000000 BUSD (0.00000000 USD) 245 | Available TRX: 0.01116951 TRX (0.00269201 USD) 246 | Available POL: 0.13433365 POL (0.06417564 USD) 247 | Available AVAX: 0.00000000 AVAX (0.00000000 USD) 248 | Available BTC: 0.00000000 BTC (0.00000000 USD) 249 | Available LTC: 0.00000136 LTC (0.00017045 USD) 250 | Available SHIB: 0.00000000 SHIB (0.00000000 USD) 251 | Available HMSTR: 0.00000000 HMSTR (0.00000000 USD) 252 | 253 | User: 254 | 255 | Available DASH: 0.00000000 DASH (0.00000000 USD) 256 | Available ETH: 0.00000000 ETH (0.00000000 USD) 257 | Available VERSE: 0.00000000 VERSE (0.00000000 USD) 258 | Available CRMS: 0.12041311 CRMS (0.12041311 USD) 259 | Available DAI: 0.00000000 DAI (0.00000000 USD) 260 | Available BUSD: 0.00000000 BUSD (0.00000000 USD) 261 | Available SOL: 0.00000000 SOL (0.00000000 USD) 262 | Available USDT: 0.00975846 USDT (0.00975097 USD) 263 | Available CGPT: 0.00000000 CGPT (0.00000000 USD) 264 | Available BNB: 0.00000000 BNB (0.00000000 USD) 265 | Available BTC: 0.00000000 BTC (0.00000000 USD) 266 | Available USDC: 0.00000000 USDC (0.00000000 USD) 267 | Available DOGE: 0.00000000 DOGE (0.00000000 USD) 268 | Available AVAX: 0.00000000 AVAX (0.00000000 USD) 269 | Available LTC: 0.00000000 LTC (0.00000000 USD) 270 | Available XMR: 0.00000000 XMR (0.00000000 USD) 271 | Available BCH: 0.00000000 BCH (0.00000000 USD) 272 | Available POL: 0.00000000 POL (0.00000000 USD) 273 | Available TON: 0.00000000 TON (0.00000000 USD) 274 | Available TRX: 0.00000000 TRX (0.00000000 USD) 275 | Available SHIB: 0.00000000 SHIB (0.00000000 USD) 276 | Available HMSTR: 0.00000000 HMSTR (0.00000000 USD) 277 | -------------- 278 | XRocket: 279 | Available TONCOIN: 0 TONCOIN 280 | Available XROCK: 0 XROCK 281 | Available SCALE: 0 SCALE 282 | Available BOLT: 0 BOLT 283 | Available TAKE: 0 TAKE 284 | Available HEDGE: 0 HEDGE 285 | Available KOTE: 0 KOTE 286 | Available TNX: 0 TNX 287 | Available GRBS: 0 GRBS 288 | Available AMBR: 0 AMBR 289 | Available JBCT: 0 JBCT 290 | Available IVS: 0 IVS 291 | Available LAVE: 0 LAVE 292 | Available DHD: 0 DHD 293 | Available KINGY: 0 KINGY 294 | Available REDX: 0 REDX 295 | Available GGT: 0 GGT 296 | Available PET: 0 PET 297 | Available JETTON: 0 JETTON 298 | Available BNB: 0 BNB 299 | Available USDT: 0 USDT 300 | Available LIFEYT: 0 LIFEYT 301 | Available GEMSTON: 0 GEMSTON 302 | Available BTC: 0 BTC 303 | Available NANO: 0 NANO 304 | Available ANON: 0 ANON 305 | Available ATL: 0 ATL 306 | Available NUDES: 0 NUDES 307 | Available WIF: 0 WIF 308 | Available MARGA: 0 MARGA 309 | Available DUREV: 0 DUREV 310 | Available SOX: 0 SOX 311 | Available UNIC: 0 UNIC 312 | Available VIRUS1: 0 VIRUS1 313 | Available ICTN: 0 ICTN 314 | Available JMT: 0 JMT 315 | Available FID: 0 FID 316 | Available CATS: 0 CATS 317 | Available WALL: 0 WALL 318 | Available NOT: 0 NOT 319 | Available OPEN: 0 OPEN 320 | Available MORFEY: 0 MORFEY 321 | Available MMM: 0 MMM 322 | Available CAVI: 0 CAVI 323 | Available ALENKA: 0 ALENKA 324 | Available TIME: 0 TIME 325 | Available CES: 0 CES 326 | Available KKX: 0 KKX 327 | Available HYDRA: 0 HYDRA 328 | Available GRC: 0 GRC 329 | Available tsTON: 0 tsTON 330 | Available STON: 0 STON 331 | Available DOGS: 0 DOGS 332 | Available TRX: 0 TRX 333 | Available PUNK: 0 PUNK 334 | Available TONNEL: 0 TONNEL 335 | Available DFC: 0 DFC 336 | Available ETH: 0 ETH 337 | Available ARBUZ: 0 ARBUZ 338 | Available UP: 0 UP 339 | Available RAFF: 0 RAFF 340 | Available DRIFT: 0 DRIFT 341 | Available FISH: 0 FISH 342 | Available MEOW: 0 MEOW 343 | Available TINU: 0 TINU 344 | Available BLKC: 0 BLKC 345 | Available PROTON: 0 PROTON 346 | Available GRAM: 0 GRAM 347 | Available WEB3: 0 WEB3 348 | Available MRDN: 0 MRDN 349 | Available LKY: 0 LKY 350 | Available STBL: 0 STBL 351 | Available 1RUSD: 0 1RUSD 352 | Available JVT: 0 JVT 353 | Available DRA: 0 DRA 354 | Available STATHAM: 0 STATHAM 355 | Available SHEEP: 0 SHEEP 356 | Available PLANKTON: 0 PLANKTON 357 | Available MUMBA: 0 MUMBA 358 | Available VWS: 0 VWS 359 | Available LAIKA: 0 LAIKA 360 | Available SAU: 0 SAU 361 | Available GOY: 0 GOY 362 | Available BUFFY: 0 BUFFY 363 | Available PIZZA: 0 PIZZA 364 | Available SOL: 0 SOL 365 | Available SLOW: 0 SLOW 366 | Available THNG: 0 THNG 367 | Available SP: 0 SP 368 | Available AQUAXP: 0 AQUAXP 369 | Available CATI: 0 CATI 370 | Available HMSTR: 0 HMSTR 371 | Available STORM: 0 STORM 372 | Available SPN: 0 SPN 373 | Available JETTY: 0 JETTY 374 | Available MAJOR: 0 MAJOR 375 | Available FTON: 0 FTON 376 | Available CATSTG: 0 CATSTG 377 | Available BUILD: 0 BUILD 378 | Available TRUMP: 0 TRUMP 379 | ------------------------------------------ 380 | PayOK: https://payok.io//pay?amount=15&payment=4364575733&shop=12452¤cy=RUB&desc=Description&sign=af2fdc6796750e3c6910230095ec0ed8 381 | FreeKassa: https://pay.freekassa.com/form/161328352/576046439bd01de60a6e418bad9354a2 382 | RuKassa: https://pay.ruks.pro/?hash=435fc3cee737f9dac2b34c9ba9311eae 383 | Lolz: https://lzt.market/invoice/369/ 384 | Aaio: https://aaio.io/merchant/pay?merchant_id=f398c75d-b775-412c-9674-87939692c083&amount=15&order_id=orderId¤cy=RUB&sign=6ad5dc2164059a255921ad216c7e5ffd0d2abcaec9af7415636fc12df938582f 385 | CryptoBot: https://t.me/CryptoBot?start=IVYOJWPOZh15 386 | CrystalPay: https://pay.crystalpay.io/?i=715308958_rPwTzvsvCmabwl 387 | Cryptomus: https://pay.cryptomus.com/pay/6c0j685d-2bc1-41a1-954b-b11def3641a4 388 | XRocket: https://t.me/xrocket?start=inv_NX9RajMus37wbn3 389 | ------------------------------------------ 390 | PayOK: 391 | Amount: 15 392 | Status: 0 393 | -------------- 394 | FreeKassa: 395 | Amount: 150 396 | Status: 0 397 | -------------- 398 | RuKassa: 399 | Amount: 50 400 | Status: WAIT 401 | -------------- 402 | Lolz: 403 | Amount: 15 404 | Status: not_paid 405 | -------------- 406 | Aaio: 407 | Amount: 299.0 408 | Status: in_process 409 | -------------- 410 | CryptoBot: 411 | Amount: 15 412 | Status: active 413 | -------------- 414 | CrystalPay: 415 | Amount: 15 416 | Status: notpayed 417 | -------------- 418 | Cryptomus: 419 | Amount: 15.00 420 | Status: check 421 | -------------- 422 | XRocket: 423 | Amount: 1.0 424 | Status: active 425 | 426 | ``` 427 | 428 | ## Docs 429 | > Lolzteam Market: https://lzt-market.readme.io/reference/
430 | > Aaio: https://wiki.aaio.io
431 | > CryptoBot: https://help.crypt.bot/crypto-pay-api
432 | > CrystalPay: https://docs.crystalpay.io/
433 | > RuKassa: https://lk.rukassa.pro/api/v1
434 | > FreeKassa: https://docs.freekassa.com/
435 | > PayOK: https://payok.io/cabinet/documentation/doc_main.php
436 | > Cryptomus: https://doc.cryptomus.com/business
437 | > XRocket: https://pay.xrocket.tg/api/#/
438 | 439 | ## Developer Links 440 | > Zelenka (Lolzteam): https://lzt.market/tosa
441 | > GitHub: https://github.com/I-ToSa-I
442 | > Telegram: https://t.me/ToSa_LZT 443 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "setuptools-scm"] 3 | build-backend = "setuptools.build_meta" 4 | [project] 5 | name = "AsyncPayments" 6 | version = "1.4.7" 7 | dependencies = [ 8 | "aiohttp" 9 | ] 10 | requires-python = ">= 3.9" 11 | authors = [ 12 | { name = "ToSa" }, 13 | ] 14 | maintainers = [ 15 | { name = "ToSa" } 16 | ] 17 | description = "Add payment acceptance to your projects." 18 | readme = "README.md" 19 | license = {text = "MIT License"} 20 | keywords = [ 21 | "async", 22 | "payments", 23 | "aaio", 24 | "crypto bot", 25 | "crystal pay", 26 | "async payments", 27 | "free kassa", 28 | "ru kassa", 29 | "cryptomus", 30 | "xrocket", 31 | "payok" 32 | ] 33 | classifiers = [ 34 | "Development Status :: 5 - Production/Stable", 35 | "Natural Language :: Russian", 36 | "Natural Language :: English", 37 | "Programming Language :: Python", 38 | "Programming Language :: Python :: 3 :: Only", 39 | "Programming Language :: Python :: 3.9", 40 | "Programming Language :: Python :: 3.10", 41 | "Programming Language :: Python :: 3.11", 42 | "Topic :: Utilities" 43 | ] 44 | [project.urls] 45 | Homepage = "https://github.com/I-ToSa-I/AsyncPayments" 46 | Repository = "https://github.com/I-ToSa-I/AsyncPayments" 47 | Issues = "https://github.com/I-ToSa-I/AsyncPayments/issues" 48 | --------------------------------------------------------------------------------