Welcome to the glQiwiApi documentation!#

Latest version released on PyPi python version downloads per month number of downloads for all time code grade code coverage CI

Danger

glQiwiApi 2.x has breaking changes. It breaks backwards compatibility by introducing new breaking changes!

Features:#

  • It’s working faster than other async wrappers for qiwi and yoomoney see here

  • Obviously, it’s asynchronous

  • Fully supports qiwi apis: qiwi-maps, bills, wallet and also yoomoney

  • Provides support of polling and webhooks for QIWI as well as possible

  • Furnishes many utils and extensions such a pydantic support, code coverage not less than 80% and many other handy things

  • Full compatibility with static type checking(mypy)

Quick example#

import asyncio

from glQiwiApi import QiwiWallet
from glQiwiApi.qiwi.exceptions import QiwiAPIError


async def print_balance(qiwi_token: str, phone_number: str) -> None:
    """
    This function allows you to get balance of your wallet using glQiwiApi library
    """
    async with QiwiWallet(api_access_token=qiwi_token, phone_number=phone_number) as w:
        try:
            balance = await w.get_balance()
        # handle exception if wrong credentials or really API return error
        except QiwiAPIError as err:
            print(err.json())
            raise
    print(f"Your current balance is {balance.amount} {balance.currency.name}")


asyncio.run(print_balance(qiwi_token="qiwi api token", phone_number="+phone_number"))

Contents#

Installation#

Tip

Supported Python versions: 3.7 and higher

Stable release#

In order to install glQiwiApi, run this command in your terminal:

$ pip install glQiwiApi

This is the preferred installation method as it will always install the most recent stable release. If you do not have installed pip, this Python Installation Reference can help you in the process.

From source files#

You can either clone the public repository:

$ git clone -b dev-2.x git://github.com/GLEF1X/glQiwiApi

Once you get a copy of the source files, you can install them with:

$ python setup.py install

Recommendations#

You can hasten api by following the instructions below:

  • Use uvloop instead of default asyncio loop.

    uvloop is a rapid, drop-in replacement of the built-in asyncio event loop. uvloop is implemented in Cython and uses libuv under the hood.

    Installation:

    $ pip install uvloop
    
  • Use orjson instead of the default json module.

    orjson is a rapid, correct JSON library for Python. It benchmarks as the fastest Python library for JSON and is more correct than the standard json library or other third-party libraries

    Installation:

    $ pip install orjson
    

Getting started#

QIWI#

This section covers the most popular use cases of glQiwiApi.

How can I retrieve history?#

import asyncio

from glQiwiApi import QiwiWallet


async def get_history(qiwi_token: str, phone_number: str) -> None:
    async with QiwiWallet(api_access_token=qiwi_token, phone_number=phone_number) as wallet:
        for transaction in await wallet.history():
            # handle


asyncio.run(get_history(qiwi_token="qiwi api token", phone_number="+phone number"))

How can I transfer money to other wallet?#

import asyncio

from glQiwiApi import QiwiWallet


async def transfer_money_to_another_wallet(qiwi_token: str, phone_number: str) -> None:
    async with QiwiWallet(api_access_token=qiwi_token, phone_number=phone_number) as wallet:
        await wallet.transfer_money(to_phone_number="+754545343", amount=1)


asyncio.run(transfer_money_to_another_wallet(qiwi_token="token", phone_number="+phone number"))

How can I transfer money to other card?#

import asyncio

from glQiwiApi import QiwiWallet


async def transfer_money_to_card(qiwi_token: str, phone_number: str) -> None:
    async with QiwiWallet(api_access_token=qiwi_token, phone_number=phone_number) as wallet:
        await wallet.transfer_money_to_card(card_number="desired card number", amount=50)


asyncio.run(transfer_money_to_card(qiwi_token="token", phone_number="+phone number"))

How can I gracefully handle exceptions that may return API?#

In most cases you just wrap the statement with method of API with try/except and then on demand get message(in json or plain text) and log it

import asyncio

from glQiwiApi import QiwiWallet
from glQiwiApi.qiwi.exceptions import QiwiAPIError


async def main():
    async with QiwiWallet(api_access_token="",
                          phone_number="+") as wallet:
        try:
            await wallet.transfer_money(to_phone_number="wrong number", amount=-1)
        except QiwiAPIError as ex:
            ex.json()  # json response from API
            print(ex)  # full traceback


asyncio.run(main())

How to interact with P2P API?#

To create p2p bill you have to utilize create_p2p_bill method.

import asyncio

from glQiwiApi import QiwiP2PClient


async def create_p2p_bill():
    async with QiwiP2PClient(secret_p2p="your p2p token") as p2p:
        bill = await p2p.create_p2p_bill(amount=1)
        print(f"Link to pay bill with {bill.id} id = {bill.pay_url}")


asyncio.run(create_p2p_bill())

If you go to the created link, you will see this:

bill form example

Obviously, you have to check this bill someway. You can use handy label p2p.check_if_bill_was_paid or do it in standard way p2p.get_bill_status(bill.bill_id) and then check that status equals appropriate value.

Tip

To reject p2p bill you should use reject_p2p_bill or label p2p.reject()

from glQiwiApi import QiwiP2PClient


async def create_and_check_p2p_bill():
    async with QiwiP2PClient(secret_p2p="your p2p token") as p2p:
        bill = await p2p.create_p2p_bill(amount=777)
        if await p2p.check_if_bill_was_paid(bill):
            # some logic

Issue with referrer#

> QIWI block wallets users of which go to p2p pages from messengers, email and other services.

Currently, It’s solved by reverse proxy, that deployed directly to AWS beanstalk.

Bill.shim_url property is a proxy url, that can be used to add referrer and try to avoid of blocking wallet.

import asyncio

from glQiwiApi import QiwiP2PClient


async def main():
    async with QiwiP2PClient(
            secret_p2p="Your secret p2p api key",
            shim_server_url="http://referrerproxy-env.eba-cxcmwwm7.us-east-1.elasticbeanstalk.com/proxy/p2p/"
        ) as client:
        bill = await client.create_p2p_bill(amount=1)
        shim_url = client.create_shim_url(bill)


asyncio.run(main())

But also you can transmit your own shim url directly to QiwiP2PClient constructor:

import asyncio

from glQiwiApi import QiwiP2PClient


async def main():
    async with QiwiP2PClient(
            secret_p2p="Your secret p2p api key",
            shim_server_url="https://some.url/your_proxy_path/"
    ) as client:
        bill = await client.create_p2p_bill(amount=1)
        shim_url = client.create_shim_url(bill.invoice_uid)


asyncio.run(main())

Run referrer proxy manually#

For more information go to the proxy repository on GitHub: Official referer proxy repository

Using docker:

docker pull ghcr.io/glef1x/glqiwiapi-proxy:latest
docker run -p 80:80 ghcr.io/glef1x/glqiwiapi-proxy:latest

More methods you can figure out in autogenerated API docs

Usage with aiogram#

Without middleware#
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.utils import executor

from glQiwiApi import QiwiP2PClient
from glQiwiApi.qiwi.clients.p2p.types import Bill

qiwi_p2p_client = QiwiP2PClient(secret_p2p="YOUR_SECRET_P2P_TOKEN")

BOT_TOKEN = "BOT_TOKEN"

bot = Bot(token=BOT_TOKEN, parse_mode=types.ParseMode.HTML)
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)


@dp.message_handler(text="I want to pay")
async def handle_creation_of_payment(message: types.Message, state: FSMContext):
    async with qiwi_p2p_client:
        bill = await qiwi_p2p_client.create_p2p_bill(amount=1)
    await message.answer(text=f"Ok, here's your invoice:\n {bill.pay_url}")
    await state.set_state("payment")
    await state.update_data(bill=bill)


@dp.message_handler(state="payment", text="I have paid this invoice")
async def handle_successful_payment(message: types.Message, state: FSMContext):
    async with state.proxy() as data:
        bill: Bill = data.get("bill")

    if await qiwi_p2p_client.check_if_bill_was_paid(bill):
        await message.answer("You have successfully paid your invoice")
        await state.finish()
    else:
        await message.answer("Invoice was not paid")


if __name__ == "__main__":
    executor.start_polling(dp, skip_updates=True)
With middleware#
import asyncio
import logging
from typing import Dict, Any

from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.middlewares import LifetimeControllerMiddleware
from aiogram.types.base import TelegramObject

from glQiwiApi import QiwiP2PClient
from glQiwiApi.qiwi.clients.p2p.types import Bill

BOT_TOKEN = "BOT TOKEN"


class EnvironmentMiddleware(LifetimeControllerMiddleware):
    def __init__(self, qiwi_p2p_client: QiwiP2PClient):
        super().__init__()
        self._qiwi_p2p_client = qiwi_p2p_client

    async def pre_process(self, obj: TelegramObject, data: Dict[str, Any], *args: Any) -> None:
        data["qiwi_p2p_client"] = self._qiwi_p2p_client


async def handle_creation_of_payment(
    message: types.Message, state: FSMContext, qiwi_p2p_client: QiwiP2PClient
):
    async with qiwi_p2p_client:
        bill = await qiwi_p2p_client.create_p2p_bill(amount=1)
    await message.answer(text=f"Ok, here's your invoice:\n {bill.pay_url}")
    await state.set_state("payment")
    await state.update_data(bill=bill)


async def handle_successful_payment(
    message: types.Message, state: FSMContext, qiwi_p2p_client: QiwiP2PClient
):
    async with state.proxy() as data:
        bill: Bill = data.get("bill")

    if await qiwi_p2p_client.check_if_bill_was_paid(bill):
        await message.answer("You have successfully paid your invoice")
        await state.finish()
    else:
        await message.answer("Invoice was not paid")


async def main():
    bot = Bot(token=BOT_TOKEN, parse_mode=types.ParseMode.HTML)
    storage = MemoryStorage()
    dp = Dispatcher(bot, storage=storage)
    dp.middleware.setup(
        EnvironmentMiddleware(
            qiwi_p2p_client=QiwiP2PClient(
                secret_p2p=""
            )
        )
    )

    dp.register_message_handler(handle_creation_of_payment, text="I want to pay")
    dp.register_message_handler(
        handle_successful_payment, state="payment", text="I have paid this invoice"
    )

    # start
    try:
        await dp.start_polling()
    finally:
        await dp.storage.close()
        await dp.storage.wait_closed()
        await bot.session.close()


logging.basicConfig(level=logging.DEBUG)
if __name__ == "__main__":
    asyncio.run(main())

YooMoney#

How to obtain the API token#

Firstly, you have to register our application in YooMoney using the link: click.

So, you will be redirected to the same page:

example of registration form

It goes without saying, we get the client_id after registration and then use YooMoneyAPI. Here is brief example how to obtain url to get special code

import asyncio

from glQiwiApi import YooMoneyAPI


async def get_url_to_auth() -> None:
    # Get a link for authorization, follow it if we get invalid_request or some kind of error
    # means either the scope parameter is incorrectly passed, you need to reduce the list of rights or try to recreate the application
    print(await YooMoneyAPI.build_url_for_auth(
        # For payments, account verification and payment history, you need to specify scope = ["account-info", "operation-history", "operation-details", "payment-p2p"]
        scope=["account-info", "operation-history"],
        client_id='ID received when registering the application above',
        redirect_uri='the link specified during registration above in the Redirect URI field'
    ))


asyncio.run(get_url_to_auth())

Tip

In the url you will see your code as a default param of GET request e.g. https://example.com/?code=bla-bla-bla

Now you need to get the temporary code and get the token as fast as possible using the YooMoneyAPI class method:

import asyncio

from glQiwiApi import YooMoneyAPI


async def get_token() -> None:
    print(await YooMoneyAPI.get_access_token(
        code='the code obtained from the link',
        client_id='Application ID received when registering the application above',
        redirect_uri='link provided during registration'
    ))


asyncio.run(get_token())

Examples#

Dive-in example.

import asyncio

from glQiwiApi import YooMoneyAPI

TOKEN = 'your token'


async def main():
    async with YooMoneyAPI(api_access_token=TOKEN) as w:
        print(await w.operation_history(records=50))


asyncio.run(main())

Creating pay form.

Tip

This method is extremely weightless, cause it doesn’t send any request.

from glQiwiApi import YooMoneyAPI

TOKEN = 'your token'

link = YooMoneyAPI.create_pay_form(
    receiver="4100116602400968",
    quick_pay_form="donate",
    targets="donation",
    payment_type="PC",
    amount=50
)

print(link)

Send money to another wallet and checking this transaction

import asyncio

from glQiwiApi import YooMoneyAPI

TOKEN = 'your_token'


async def main():
    w = YooMoneyAPI(TOKEN)
    async with w:
        # So you can send funds to another account, in the example this is a transfer to account 4100116602400968
        # worth 2 rubles with the comment "I LOVE glQiwiApi"
        payment = await w.transfer_money(
            to_account='4100116602400968',
            comment='I LOVE glQiwiApi',
            amount=2
        )
        # This way you can check the transaction, whether it was received by the person on the account
        print(await w.check_if_operation_exists(
            check_fn=lambda o: o.id == payment.payment_id
        ))


asyncio.run(main())

Fetch account info.

import asyncio

from glQiwiApi import YooMoneyAPI

TOKEN = 'your_token'


async def main():
    w = YooMoneyAPI(TOKEN)
    async with w:
        # This gives you account information as AccountInfo pydantic model.
        get_account_info = await w.retrieve_account_info()
        print(get_account_info.account_status)
        print(get_account_info.balance)


asyncio.run(main())

Available API wrappers#

The glQiwiApi is capable of interacting with many APIs independently. Actually, there is no restrictions to usage of both YooMoney and QIWI API.

QIWI API#

class glQiwiApi.qiwi.clients.wrapper.QiwiWrapper(api_access_token: Optional[str] = None, phone_number: Optional[str] = None, secret_p2p: Optional[str] = None, cache_time_in_seconds: Union[float, int] = 0, *args: Any, **kwargs: Any)[source]#

Bases: object

For backward compatibility with glQiwiApi <= 1.1.4

__init__(api_access_token: Optional[str] = None, phone_number: Optional[str] = None, secret_p2p: Optional[str] = None, shim_server_url: Optional[str] = None) None[source]#
async get_balance(*, account_number: int = 1) glQiwiApi.types.amount.AmountWithCurrency[source]#
async get_nickname() glQiwiApi.qiwi.clients.wallet.types.nickname.NickName[source]#
async transactions(rows: int = 50, operation: glQiwiApi.qiwi.clients.wallet.types.transaction.TransactionType = TransactionType.ALL, sources: Optional[List[glQiwiApi.qiwi.clients.wallet.types.transaction.Source]] = None, start_date: Optional[datetime.datetime] = None, end_date: Optional[datetime.datetime] = None, next_txn_date: Optional[datetime.datetime] = None, next_txn_id: Optional[int] = None) glQiwiApi.qiwi.clients.wallet.types.transaction.History[source]#

Method for receiving transactions on the account More detailed documentation: https://developer.qiwi.com/ru/qiwi-wallet-personal/?http#payments_list

Parameters
  • rows – number of transactions you want to receive

  • operation – The type of operations in the report for selection.

  • sources – List of payment sources, for filter

  • start_date – The starting date for searching for payments. Used only in conjunction with end_date.

  • end_date – the end date of the search for payments. Used only in conjunction with start_date.

  • next_txn_id

  • next_txn_date

async transaction_info(transaction_id: Union[str, int], transaction_type: glQiwiApi.qiwi.clients.wallet.types.transaction.TransactionType) glQiwiApi.qiwi.clients.wallet.types.transaction.Transaction[source]#

Method for obtaining complete information about a transaction

Detailed documentation: https://developer.qiwi.com/ru/qiwi-wallet-personal/?python#txn_info

Parameters
  • transaction_id

  • transaction_type – only IN or OUT

Returns

Transaction object

async get_restriction() List[glQiwiApi.qiwi.clients.wallet.types.restriction.Restriction][source]#

Method to check limits on your qiwi wallet Detailed documentation: https://developer.qiwi.com/ru/qiwi-wallet-personal/?python#restrictions

Returns

List where the dictionary is located with restrictions, if there are no restrictions, it returns an empty list

async get_identification() glQiwiApi.qiwi.clients.wallet.types.identification.Identification[source]#

This method allows get your wallet identification data More detailed documentation: https://developer.qiwi.com/ru/qiwi-wallet-personal/?http#ident

async check_transaction(amount: Union[int, float], transaction_type: glQiwiApi.qiwi.clients.wallet.types.transaction.TransactionType = TransactionType.IN, sender: Optional[str] = None, rows_num: int = 50, comment: Optional[str] = None) bool[source]#

[ NON API METHOD ]

Method for verifying a transaction. This method uses self.transactions (rows = rows) “under the hood” to check payment.

For a little optimization, you can decrease rows by setting it, however, this does not guarantee the correct result

Possible values for the transaction_type parameter:
  • ‘IN’

  • ‘OUT’

  • ‘QIWI_CARD’

Parameters
  • amount – amount of payment

  • transaction_type – type of payment

  • sender – number of receiver

  • rows_num – number of payments to be checked

  • comment – comment by which the transaction will be verified

async check_whether_transaction_exists(check_fn: Callable[[glQiwiApi.qiwi.clients.wallet.types.transaction.Transaction], bool], rows_num: int = 50) bool[source]#
async get_limits(limit_types: List[str] = ['TURNOVER', 'REFILL', 'PAYMENTS_P2P', 'PAYMENTS_PROVIDER_INTERNATIONALS', 'PAYMENTS_PROVIDER_PAYOUT', 'WITHDRAW_CASH']) Dict[str, glQiwiApi.qiwi.clients.wallet.types.limit.Limit][source]#

Function for getting limits on the qiwi wallet account Returns wallet limits as a list, if there is no limit for a certain country, then it does not include it in the list Detailed documentation:

https://developer.qiwi.com/ru/qiwi-wallet-personal/?http#limits

async get_list_of_cards() List[glQiwiApi.qiwi.clients.wallet.types.qiwi_master.Card][source]#
async authenticate(birth_date: str, first_name: str, last_name: str, middle_name: str, passport: str, oms: Optional[str] = None, inn: Optional[str] = None, snils: Optional[str] = None) Dict[str, Any][source]#

This request allows you to transfer_money data to identify your QIWI wallet. It is allowed to identify no more than 5 wallets per owner

To identify the wallet, you must transfer_money your full name, passport series number and date of birth. If the data has been verified, then the response will display your TIN and simplified wallet identification will be installed. If the data has not been verified, the wallet remains in the “Minimum” status.

Parameters
  • birth_date – Date of birth as a format string 1998-02-11

  • first_name – First name

  • last_name – Last name

  • middle_name – Middle name

  • passport – Series / Number of the passport. Ex: 4400111222

  • oms

  • snils

  • inn

async get_receipt(transaction_id: Union[str, int], transaction_type: glQiwiApi.qiwi.clients.wallet.types.transaction.TransactionType, file_format: str = 'PDF') glQiwiApi.types.arbitrary.file.File[source]#

Method for receiving a receipt in byte format or file.

Possible transaction_type values:
  • ‘IN’

  • ‘OUT’

  • ‘QIWI_CARD’

Parameters
  • transaction_id – transaction id, can be obtained by calling the transfer_money method, transfer_money_to_card

  • transaction_type – type of transaction: ‘IN’, ‘OUT’, ‘QIWI_CARD’

  • file_format – format of file

async get_account_info() glQiwiApi.qiwi.clients.wallet.types.account_info.UserProfile[source]#
async fetch_statistics(start_date: datetime.datetime, end_date: datetime.datetime, operation: glQiwiApi.qiwi.clients.wallet.types.transaction.TransactionType = TransactionType.ALL, sources: Optional[List[str]] = None) glQiwiApi.qiwi.clients.wallet.types.stats.Statistic[source]#

This query is used to get summary statistics by the amount of payments for a given period. More detailed documentation: https://developer.qiwi.com/ru/qiwi-wallet-personal/?http#payments_list

:param start_date:The start date of the statistics period. :param end_date: End date of the statistics period. :param operation: The type of operations taken into account when calculating statistics.

Allowed values:

ALL - все операции, IN - только пополнения, OUT - только платежи, QIWI_CARD - только платежи по картам QIWI (QVC, QVP). По умолчанию ALL.

Parameters

sources – The sources of payments QW_RUB - рублевый счет кошелька, QW_USD - счет кошелька в долларах, QW_EUR - счет кошелька в евро, CARD - привязанные и непривязанные к кошельку банковские карты, MK - счет мобильного оператора. Если не указан, учитываются все источники платежа.

async list_of_balances() List[glQiwiApi.qiwi.clients.wallet.types.balance.Balance][source]#

The request gets the current account balances of your QIWI Wallet. More detailed documentation: https://developer.qiwi.com/ru/qiwi-wallet-personal/?http#balances_list

async create_new_balance(currency_alias: str) Dict[str, bool][source]#

The request creates a new account and balance in your QIWI Wallet

Parameters

currency_alias – New account alias

async available_balances() List[glQiwiApi.qiwi.clients.wallet.types.balance.AvailableBalance][source]#

The request displays account aliases, available for creation in your QIWI Wallet

async set_default_balance(currency_alias: str) Dict[Any, Any][source]#

The request sets up an account for your QIWI Wallet, whose balance will be used for funding all payments by default. The account must be contained in the list of accounts, you can get the list by calling get_list_of_balances method

Parameters

currency_alias

to_wallet(to_number: str, amount: Union[int, float, str], currency: str = '643', comment: Optional[str] = None) glQiwiApi.qiwi.clients.wallet.types.payment_info.PaymentInfo[source]#
async transfer_money(to_phone_number: str, amount: Union[int, float, str], comment: Optional[str] = None) glQiwiApi.qiwi.clients.wallet.types.payment_info.PaymentInfo[source]#

Method for transferring funds to wallet

Detailed documentation: https://developer.qiwi.com/ru/qiwi-wallet-personal/?python#p2p

Parameters
  • to_phone_number – recipient number

  • amount – the amount of money you want to transfer

  • comment – payment comment

to_card(trans_sum: Union[float, int], to_card: str) glQiwiApi.qiwi.clients.wallet.types.payment_info.PaymentInfo[source]#
async transfer_money_to_card(card_number: str, *, amount: Union[int, float]) glQiwiApi.qiwi.clients.wallet.types.payment_info.PaymentInfo[source]#

Method for sending funds to the card.

More detailed documentation: https://developer.qiwi.com/ru/qiwi-wallet-personal/#cards

async predict_commission(to_account: str, pay_sum: Union[int, float]) glQiwiApi.qiwi.clients.wallet.types.commission.Commission[source]#

Full calc_commission of QIWI Wallet is refunded for payment in favor of the specified provider taking into account all tariffs for a given set of payment details.

Parameters
  • to_account

  • pay_sum

Returns

Commission object

async get_cross_rates() List[glQiwiApi.qiwi.clients.wallet.types.other.CrossRate][source]#

The method returns the current exchange rates and cross-rates of the QIWI Bank’s currencies.

async payment_by_payment_details(payment_sum: glQiwiApi.types.amount.AmountWithCurrency, payment_method: glQiwiApi.qiwi.clients.wallet.types.other.PaymentMethod, fields: glQiwiApi.qiwi.clients.wallet.types.other.PaymentDetails, payment_id: Optional[str] = None) glQiwiApi.qiwi.clients.wallet.types.payment_info.PaymentInfo[source]#

Payment for services of commercial organizations according to their bank details.

Parameters
  • payment_id – payment id, if not transmitted, is used uuid4 by default

  • payment_sum – a Sum object, which indicates the amount of the payment

  • payment_method – payment method

  • fields – payment details

async buy_qiwi_master() glQiwiApi.qiwi.clients.wallet.types.payment_info.PaymentInfo[source]#

Method for buying QIWI Master package To call API methods, you need the QIWI Wallet API token with permissions to do the following: 1. Management of virtual cards, 2. Request information about the wallet profile, 3. View payment history, 4. Making payments without SMS. You can choose these rights when creating a new api token, to use api QIWI Master

async issue_qiwi_master_card(card_alias: str = 'qvc-cpa') Optional[glQiwiApi.qiwi.clients.wallet.types.qiwi_master.OrderDetails][source]#

Issuing a new card using the Qiwi Master API

When issuing a card, 3, and possibly 3 requests are made, namely, according to the following scheme:

  • _create_card_purchase_order - this method creates a request

  • _confirm_qiwi_master_purchase_order - confirms the issue of the card

  • _buy_new_qiwi_master_card - buys a new card, if such a card is not free

Detailed documentation: https://developer.qiwi.com/ru/qiwi-wallet-personal/#qiwi-master-issue-card

async register_webhook(web_url: str, txn_type: int = 2) glQiwiApi.qiwi.clients.wallet.types.webhooks.WebhookInfo[source]#

This method register a new webhook

Parameters
  • web_url – service endpoint

  • txn_type – 0 => incoming, 1 => outgoing, 2 => all

Returns

Active Hooks

async get_current_webhook() glQiwiApi.qiwi.clients.wallet.types.webhooks.WebhookInfo[source]#

List of active (active) notification handlers, associated with your wallet can be obtained with this request. Since now only one type of hook is used - webhook, then the response contains only one data object

async send_test_notification() Dict[str, Any][source]#

Use this request to test your webhooks handler. Test notification is sent to the address specified during the call register_webhook

async get_webhook_secret_key(hook_id: str) str[source]#

Each notification contains a digital signature of the message, encrypted with a key. To obtain a signature verification key, use this request.

Parameters

hook_id – UUID of webhook

Returns

Base64 encoded key

async delete_current_webhook() Dict[str, Any][source]#

Method to delete webhook

async change_webhook_secret(hook_id: str) str[source]#

Use this request to change the encryption key for notifications.

Parameters

hook_id – UUID of webhook

Returns

Base64 encoded key

async bind_webhook(url: Union[str, WebhookURL], transactions_type: int = 2, *, send_test_notification: bool = False, delete_old: bool = False) Tuple[glQiwiApi.qiwi.clients.wallet.types.webhooks.WebhookInfo, str][source]#

[NON-API] EXCLUSIVE method to register new webhook or get old

Parameters
  • url – service endpoint

  • transactions_type – 0 => incoming, 1 => outgoing, 2 => all

  • send_test_notification – test_qiwi will transfer_money you test webhook update

  • delete_old – boolean, if True - delete old webhook

Returns

Tuple of Hook and Base64-encoded key

async detect_mobile_operator(phone_number: str) glQiwiApi.qiwi.clients.wallet.types.mobile_operator.MobileOperator[source]#
async reject_bill_by_id(bill_id: str) glQiwiApi.qiwi.clients.p2p.types.Bill[source]#

Use this method to cancel unpaid invoice.

async reject_bill(bill: glQiwiApi.qiwi.clients.p2p.types.Bill) glQiwiApi.qiwi.clients.p2p.types.Bill[source]#
async check_p2p_bill_status(bill_id: str) str[source]#

Method for checking the status of a p2p transaction.

Possible transaction types:

WAITING Bill is waiting for pay

PAID Bill was paid

REJECTED Bill was rejected

EXPIRED The bill has expired. Invoice not paid

Docs: https://developer.qiwi.com/ru/p2p-payments/?shell#invoice-status

Parameters

bill_id

Returns

status of bill

async check_if_bill_was_paid(bill: glQiwiApi.qiwi.clients.p2p.types.Bill) bool[source]#
async create_p2p_bill(amount: Union[int, float], bill_id: Optional[str] = None, comment: Optional[str] = None, life_time: Optional[datetime.datetime] = None, theme_code: Optional[str] = None, pay_source_filter: Optional[List[str]] = None, customer: Optional[glQiwiApi.qiwi.clients.p2p.types.Customer] = None) glQiwiApi.qiwi.clients.p2p.types.Bill[source]#

It is the reliable method for integration. Parameters are sent by means of server2server requests with authorization. Method allows you to issue an invoice, successful

response contains payUrl link to redirect client on Payment Form.

Possible values of pay_source_filter:
  • ‘qw’

  • ‘card’

  • ‘mobile’

Parameters
  • amount – amount of payment

  • bill_id – unique transaction number, if not transmitted, generated automatically,

  • life_time – the date until which the invoice will be available for payment.

  • comment

  • theme_code

  • pay_source_filter – When you open the form, the following will be displayed only the translation methods specified in this parameter

  • customer

async retrieve_bills(rows: int, statuses: str = 'READY_FOR_PAY') List[glQiwiApi.qiwi.clients.p2p.types.Bill][source]#

A method for getting a list of your wallet’s outstanding bills.

The list is built in reverse chronological order.

By default, the list is paginated with 50 items each, but you can specify a different number of elements (no more than 50).

Filters by billing time can be used in the request, the initial account identifier.

async pay_the_invoice(invoice_uid: str, currency: str) glQiwiApi.qiwi.clients.p2p.types.InvoiceStatus[source]#

Execution of unconditional payment of the invoice without SMS-confirmation.

! Warning ! To use this method correctly you need to tick “Проведение платежей без SMS” when registering QIWI API and retrieve token

Parameters
  • invoice_uid – Bill ID in QIWI system

  • currency

async refund_bill(bill_id: Union[str, int], refund_id: Union[str, int], json_bill_data: Union[glQiwiApi.types.amount.PlainAmount, Dict[str, Union[str, int]]]) glQiwiApi.qiwi.clients.p2p.types.RefundedBill[source]#
The method allows you to make a refund on a paid invoice.

in the JSON body of the request for the json_bill_data parameter: amount.value - refund amount. amount.currency - return currency.

Can be a dictionary or an OptionalSum object

Dictionary example: {

“amount”: {

“currency”: “RUB”, “value”: 1 }

}

Parameters
  • bill_id – unique account identifier in the merchant’s system

  • refund_id – unique identifier of the refund in the merchant’s system.

  • json_bill_data

Returns

RefundBill object

async create_p2p_keys(key_pair_name: str, server_notification_url: Optional[str] = None) glQiwiApi.qiwi.clients.p2p.types.PairOfP2PKeys[source]#

Creates a new pair of P2P keys to interact with P2P QIWI API

Parameters
  • key_pair_name – P2P token pair name

  • server_notification_url – endpoint for webhooks

create_shim_url(invoice_uid: str) str[source]#
async close() None[source]#
class glQiwiApi.qiwi.clients.wallet.client.QiwiWallet(api_access_token: str, phone_number: Optional[str] = None, request_service_factory: Optional[Callable[[...], Union[Awaitable[RequestServiceProto], RequestServiceProto]]] = None)[source]#

Bases: glQiwiApi.core.abc.base_api_client.BaseAPIClient

__init__(api_access_token: str, phone_number: Optional[str] = None, request_service_factory: Optional[Callable[[...], Union[Awaitable[RequestServiceProto], RequestServiceProto]]] = None) None[source]#
Parameters
  • api_access_token – QIWI API token received from https://qiwi.com/api

  • phone_number – your phone number starting with +

async get_profile(*args: Any, **kw: Any) Any#
async authenticate(*args: Any, **kw: Any) Any#
async get_identification(*args: Any, **kw: Any) Any#
async get_limits(*args: Any, **kw: Any) Any#
async get_restrictions(*args: Any, **kw: Any) Any#
async history(*args: Any, **kw: Any) Any#
async check_whether_transaction_exists(*args: Any, **kw: Any) Any#
async fetch_statistics(*args: Any, **kw: Any) Any#
async get_transaction_info(*args: Any, **kw: Any) Any#
async get_receipt(*args: Any, **kw: Any) Any#
async get_list_of_balances(*args: Any, **kw: Any) Any#
async get_balance(*args: Any, **kw: Any) Any#
async create_new_balance(*args: Any, **kw: Any) Any#
async detect_mobile_operator(*args: Any, **kw: Any) Any#
async get_list_of_cards(*args: Any, **kw: Any) Any#
async get_available_balances(*args: Any, **kw: Any) Any#
async set_default_balance(*args: Any, **kw: Any) Any#
async transfer_money(*args: Any, **kw: Any) Any#
async transfer_money_to_card(*args: Any, **kw: Any) Any#
async detect_card_id(*args: Any, **kw: Any) Any#
async predict_commission(*args: Any, **kw: Any) Any#
async get_cross_rates(*args: Any, **kw: Any) Any#
async payment_by_payment_details(*args: Any, **kw: Any) Any#
async buy_qiwi_master_package(*args: Any, **kw: Any) Any#
async issue_qiwi_master_card(*args: Any, **kw: Any) Any#
async get_qiwi_master_card_statement(*args: Any, **kw: Any) Any#
async block_qiwi_master_card(*args: Any, **kw: Any) Any#
async unblock_qiwi_master_card(*args: Any, **kw: Any) Any#
async get_qiwi_master_card_requisites(*args: Any, **kw: Any) Any#
async rename_qiwi_master_card(*args: Any, **kw: Any) Any#
async get_nickname(*args: Any, **kw: Any) Any#
async list_of_invoices(*args: Any, **kw: Any) Any#
async pay_the_invoice(*args: Any, **kw: Any) Any#
async register_webhook(*args: Any, **kw: Any) Any#
async get_current_webhook(*args: Any, **kw: Any) Any#
async send_test_webhook_notification(*args: Any, **kw: Any) Any#
async get_webhook_secret_key(*args: Any, **kw: Any) Any#
async delete_current_webhook(*args: Any, **kw: Any) Any#
async generate_new_webhook_secret(*args: Any, **kw: Any) Any#
async bind_webhook(*args: Any, **kw: Any) Any#
property phone_number_without_plus_sign: str#
class glQiwiApi.qiwi.clients.p2p.client.QiwiP2PClient(secret_p2p: str, request_service_factory: Optional[Callable[[...], Union[Awaitable[glQiwiApi.core.request_service.RequestServiceProto], glQiwiApi.core.request_service.RequestServiceProto]]] = None, shim_server_url: Optional[str] = None)[source]#

Bases: glQiwiApi.core.abc.base_api_client.BaseAPIClient

__init__(secret_p2p: str, request_service_factory: Optional[Callable[[...], Union[Awaitable[glQiwiApi.core.request_service.RequestServiceProto], glQiwiApi.core.request_service.RequestServiceProto]]] = None, shim_server_url: Optional[str] = None) None[source]#
Parameters
async get_bill_by_id(*args: Any, **kw: Any) Any#
async check_if_bill_was_paid(*args: Any, **kw: Any) Any#
async get_bill_status(*args: Any, **kw: Any) Any#
async create_p2p_bill(*args: Any, **kw: Any) Any#
async reject_bill(*args: Any, **kw: Any) Any#
async reject_p2p_bill(*args: Any, **kw: Any) Any#
async create_pair_of_p2p_keys(*args: Any, **kw: Any) Any#
async refund_bill(*args: Any, **kw: Any) Any#
create_shim_url(bill_or_invoice_uid: Union[glQiwiApi.qiwi.clients.p2p.types.Bill, str]) str[source]#

YooMoney API#

class glQiwiApi.yoo_money.client.YooMoneyAPI(api_access_token: str, request_service_factory: Optional[Callable[[...], Union[Awaitable[RequestServiceProto], RequestServiceProto]]] = None)[source]#

Bases: glQiwiApi.core.abc.base_api_client.BaseAPIClient

That class implements processing requests to YooMoney It is convenient in that it does not just give json such objects, and all this converts into pydantic models. To work with this class, you need to register a token, using the guide on the official github of the project

__init__(api_access_token: str, request_service_factory: Optional[Callable[[...], Union[Awaitable[RequestServiceProto], RequestServiceProto]]] = None) None[source]#
The constructor accepts a token obtained from the method class get_access_token

and the special attribute without_context

Parameters

api_access_token – api token for requests

async classmethod build_url_for_auth(scopes: List[str], client_id: str, redirect_uri: str = 'https://example.com') str[source]#

Method to get the link for further authorization and obtaining a token

Parameters
  • scopes – OAuth2 authorization of the application by the user, the rights are transferred by the list.

  • client_id – application id, type string

  • redirect_uri – a funnel where the temporary code that you need will go to to get the main token

Returns

the link to follow and make authorization via login / password

async classmethod get_access_token(code: str, client_id: str, redirect_uri: str = 'https://example.com', client_secret: Optional[str] = None) str[source]#

Method for obtaining a token for requests to the YooMoney API

Parameters
  • code – the temporary code that was obtained in the base_authorize method

  • client_id – application id, type string

  • redirect_uri – the funnel where the temporary code will go, which is needed to get the main token

  • client_secret – The secret word for authenticating the application. Specified if the service is registered with authentication.

Returns

YooMoney API TOKEN

async revoke_api_token(*args: Any, **kw: Any) Any#
classmethod create_pay_form(receiver: str, quick_pay_form: str, targets: str, payment_type: str, amount: Union[int, float], form_comment: Optional[str] = None, short_dest: Optional[str] = None, label: Optional[str] = None, comment: Optional[str] = None, success_url: Optional[str] = None, need_fio: Optional[bool] = None, need_email: Optional[bool] = None, need_phone: Optional[bool] = None, need_address: Optional[bool] = None) str[source]#

The YooMoney form is a set of fields with information about a transfer. You can embed payment form into your interface (for instance, a website or blog). When the sender pushes the button, the details from the form are sent to YooMoney and an order for a transfer to your wallet is initiated.

Detail docs: https://yoomoney.ru/docs/payment-buttons/using-api/forms?lang=en

Possible values for quick_pay_form:
  • shop - for a multi purpose form;

  • small - for a button;

  • donate - for a charity form.

@param receiver: Number of the YooMoney wallet which money from senders is credited to. @param quick_pay_form: @param targets: Payment purpose. @param payment_type: Payment method. Possible values: PC, AC, MC @param amount: Transfer amount (the amount debited from the sender). @param form_comment: Name of the transfer in sender’s history

(for transfers from a wallet or linked bank card). Displayed in sender’s wallet. The simplest way to create it is to combine the names of the store and product. For instance: My Store: white valenki boots

@param short_dest: Name of the transfer on the confirmation page.

We recommend using the same name as formcomment

@param label: The label that a site or app assigns to a certain transfer.

For instance, a code or order identifier may be used for this label.

@param comment: The field in which you can transfer_money sender’s comments. @param success_url: URL where the user is redirected after the transfer. @param need_fio: Sender’s full name required. @param need_email: Sender’s email address required. @param need_phone: Sender’s phone number required. @param need_address: Sender’s address required. @return: link to payment form

async retrieve_account_info(*args: Any, **kw: Any) Any#
async operation_history(*args: Any, **kw: Any) Any#
async operation_details(*args: Any, **kw: Any) Any#
async make_cellular_payment(*args: Any, **kw: Any) Any#
async transfer_money(*args: Any, **kw: Any) Any#
async make_request_payment(*args: Any, **kw: Any) Any#
async get_balance(*args: Any, **kw: Any) Any#
async accept_incoming_transaction(*args: Any, **kw: Any) Any#
async reject_incoming_transfer(*args: Any, **kw: Any) Any#
async check_if_operation_exists(*args: Any, **kw: Any) Any#

QIWI Maps API#

class glQiwiApi.qiwi.clients.maps.client.QiwiMaps(request_service_factory: Optional[Callable[[...], Union[Awaitable[glQiwiApi.core.request_service.RequestServiceProto], glQiwiApi.core.request_service.RequestServiceProto]]] = None)[source]#

Bases: glQiwiApi.core.abc.base_api_client.BaseAPIClient

QIWI Terminal Maps API allows you to locate QIWI terminals on the territory of the Russian Federation

__init__(request_service_factory: Optional[Callable[[...], Union[Awaitable[glQiwiApi.core.request_service.RequestServiceProto], glQiwiApi.core.request_service.RequestServiceProto]]] = None) None[source]#
async terminals(*args: Any, **kw: Any) Any#
async partners(*args: Any, **kw: Any) Any#

Polling updates#

API internals#

glQiwiApi.core.event_fetching.executor.start_polling(wallet: Union[glQiwiApi.qiwi.clients.wallet.client.QiwiWallet, glQiwiApi.qiwi.clients.wrapper.QiwiWrapper], dispatcher: glQiwiApi.core.event_fetching.dispatcher.BaseDispatcher, *plugins: glQiwiApi.plugins.abc.Pluggable, skip_updates: bool = False, timeout_in_seconds: float = 5, on_startup: Optional[Callable[[Context], Union[None, Awaitable[None]]]] = None, on_shutdown: Optional[Callable[[Context], Union[None, Awaitable[None]]]] = None, loop: Optional[asyncio.events.AbstractEventLoop] = None, context: Optional[Union[Dict[str, Any], glQiwiApi.core.event_fetching.executor.Context]] = None) None[source]#

Setup for long-polling mode. Support only glQiwiApi.types.Transaction as event.

Parameters
  • wallet – instance of QiwiWrapper

  • dispatcher

  • skip_updates

  • timeout_in_seconds – timeout of polling in seconds, if the timeout is too small, the API can throw an exception

  • on_startup – function or coroutine, which will be executed on startup

  • on_shutdown – function or coroutine, which will be executed on shutdown

  • plugins – List of plugins, that will be executed together with polling. For example builtin TelegramPollingPlugin or other class, that implement Pluggable abc interface, deal with foreign framework/application in the background

  • loop

  • context – context, that could be transmitted to handlers

async glQiwiApi.core.event_fetching.executor.start_non_blocking_qiwi_api_polling(wallet: Union[glQiwiApi.qiwi.clients.wallet.client.QiwiWallet, glQiwiApi.qiwi.clients.wrapper.QiwiWrapper], dispatcher: glQiwiApi.core.event_fetching.dispatcher.BaseDispatcher, skip_updates: bool = False, timeout_in_seconds: float = 5, on_startup: Optional[Callable[[Context], Union[None, Awaitable[None]]]] = None, on_shutdown: Optional[Callable[[Context], Union[None, Awaitable[None]]]] = None, loop: Optional[asyncio.events.AbstractEventLoop] = None, context: Optional[Union[Dict[str, Any], glQiwiApi.core.event_fetching.executor.Context]] = None) _asyncio.Task[source]#
glQiwiApi.core.event_fetching.executor.configure_app_for_qiwi_webhooks(wallet: Union[glQiwiApi.qiwi.clients.wallet.client.QiwiWallet, glQiwiApi.qiwi.clients.wrapper.QiwiWrapper], dispatcher: glQiwiApi.core.event_fetching.dispatcher.BaseDispatcher, app: aiohttp.web_app.Application, cfg: glQiwiApi.core.event_fetching.webhooks.config.WebhookConfig) aiohttp.web_app.Application[source]#
class glQiwiApi.core.event_fetching.executor.BaseExecutor(dispatcher: glQiwiApi.core.event_fetching.dispatcher.BaseDispatcher, *plugins: glQiwiApi.plugins.abc.Pluggable, context: glQiwiApi.core.event_fetching.executor.Context, loop: Optional[asyncio.events.AbstractEventLoop] = None, on_startup: Optional[Callable[[...], Any]] = None, on_shutdown: Optional[Callable[[...], Any]] = None)[source]#

Bases: abc.ABC

__init__(dispatcher: glQiwiApi.core.event_fetching.dispatcher.BaseDispatcher, *plugins: glQiwiApi.plugins.abc.Pluggable, context: glQiwiApi.core.event_fetching.executor.Context, loop: Optional[asyncio.events.AbstractEventLoop] = None, on_startup: Optional[Callable[[...], Any]] = None, on_shutdown: Optional[Callable[[...], Any]] = None) None[source]#
property loop: asyncio.events.AbstractEventLoop#
async welcome() None[source]#
async goodbye() None[source]#
class glQiwiApi.core.event_fetching.executor.PollingExecutor(wallet: Union[glQiwiApi.qiwi.clients.wallet.client.QiwiWallet, glQiwiApi.qiwi.clients.wrapper.QiwiWrapper], dispatcher: glQiwiApi.core.event_fetching.dispatcher.BaseDispatcher, *plugins: glQiwiApi.plugins.abc.Pluggable, context: glQiwiApi.core.event_fetching.executor.Context, loop: Optional[asyncio.events.AbstractEventLoop] = None, timeout: Union[float, int] = 5, skip_updates: bool = False, on_startup: Optional[Callable[[Context], Union[None, Awaitable[None]]]] = None, on_shutdown: Optional[Callable[[Context], Union[None, Awaitable[None]]]] = None)[source]#

Bases: glQiwiApi.core.event_fetching.executor.BaseExecutor

__init__(wallet: Union[glQiwiApi.qiwi.clients.wallet.client.QiwiWallet, glQiwiApi.qiwi.clients.wrapper.QiwiWrapper], dispatcher: glQiwiApi.core.event_fetching.dispatcher.BaseDispatcher, *plugins: glQiwiApi.plugins.abc.Pluggable, context: glQiwiApi.core.event_fetching.executor.Context, loop: Optional[asyncio.events.AbstractEventLoop] = None, timeout: Union[float, int] = 5, skip_updates: bool = False, on_startup: Optional[Callable[[Context], Union[None, Awaitable[None]]]] = None, on_shutdown: Optional[Callable[[Context], Union[None, Awaitable[None]]]] = None) None[source]#
start_polling() None[source]#
async start_non_blocking_polling() _asyncio.Task[source]#
async process_updates(history: glQiwiApi.qiwi.clients.wallet.types.transaction.History) None[source]#

Guidelines#

This section explains how to properly poll transactions from QIWI API.

You can’t help registering handlers and start polling, so in example above it is shown how to do it rightly. Lets do it with decorators:

️So, we also have to import executor and pass on our client, that contains functions start_polling and start_webhook.

from glQiwiApi import QiwiWallet
from glQiwiApi.core.event_fetching import executor
from glQiwiApi.core.event_fetching.dispatcher import QiwiDispatcher
from glQiwiApi.core.event_fetching.executor import Context
from glQiwiApi.core.event_fetching.filters import ExceptionFilter
from glQiwiApi.qiwi.clients.wallet.types import Transaction
from glQiwiApi.qiwi.exceptions import QiwiAPIError

qiwi_dp = QiwiDispatcher()
wallet = QiwiWallet(api_access_token='token', phone_number='+phone number')


@qiwi_dp.transaction_handler()
async def handle_transaction(t: Transaction, ctx: Context):
    """Handle transaction here"""
    ctx.wallet  # this way you can use QiwiWallet instance to avoid global variables


@qiwi_dp.exception_handler(ExceptionFilter(QiwiAPIError))
async def handle_exception(err: QiwiAPIError, ctx: Context):
    pass


if __name__ == '__main__':
    executor.start_polling(wallet, qiwi_dp)

Events#

Then, you can start polling, but, let’s make it clear which arguments you should pass on to start_polling function. You can also specify events like on_shutdown or on_startup. As you can see, in the example we have a function that we pass as an argument to on_startup. As you may have guessed, this function will be executed at the beginning of the polling.

from glQiwiApi import QiwiWallet
from glQiwiApi.core.event_fetching import executor
from glQiwiApi.core.event_fetching.dispatcher import QiwiDispatcher
from glQiwiApi.core.event_fetching.executor import Context
from glQiwiApi.qiwi.clients.wallet.types import Transaction

qiwi_dp = QiwiDispatcher()
wallet = QiwiWallet(api_access_token='token', phone_number='+phone number')


@qiwi_dp.transaction_handler()
async def handle_transaction(t: Transaction, ctx: Context):
    """Handle transaction here"""
    ctx.wallet  # this way you can use QiwiWallet instance to avoid global variables


async def on_startup(ctx: Context):
    ctx.wallet  # do something here


async def on_shutdown(ctx: Context):
    pass


if __name__ == '__main__':
    executor.start_polling(wallet, qiwi_dp, on_startup=on_startup, on_shutdown=on_shutdown)

Make aiogram work with glQiwiApi#

Also, you can very easily implement simultaneous polling of updates from both aiogram and QIWI API.

In the example below, we catch all text messages and return the same “Hello” response.

from aiogram import Bot, Dispatcher
from aiogram.types import Message

from glQiwiApi import QiwiWallet
from glQiwiApi.core.event_fetching import executor
from glQiwiApi.core.event_fetching.dispatcher import QiwiDispatcher
from glQiwiApi.core.event_fetching.executor import Context
from glQiwiApi.plugins import AiogramPollingPlugin
from glQiwiApi.qiwi.clients.wallet.types import Transaction

qiwi_dp = QiwiDispatcher()
wallet = QiwiWallet(api_access_token='token', phone_number='+phone number')

dp = Dispatcher(Bot('BOT TOKEN'))


@qiwi_dp.transaction_handler()
async def handle_transaction(t: Transaction, ctx: Context):
    """Handle transaction here"""
    ctx.wallet  # this way you can use QiwiWallet instance to avoid global variables


@dp.message_handler()
async def handle_message(msg: Message):
    await msg.answer(text='Hello world')


if __name__ == '__main__':
    executor.start_polling(wallet, qiwi_dp, AiogramPollingPlugin(dp))

Alternatively you can run polling at on_startup event

from aiogram import Bot, Dispatcher
from aiogram.types import Message
from aiogram.utils import executor

from glQiwiApi import QiwiWallet
from glQiwiApi.core.event_fetching.dispatcher import QiwiDispatcher
from glQiwiApi.core.event_fetching.executor import Context, start_non_blocking_qiwi_api_polling
from glQiwiApi.qiwi.clients.wallet.types import Transaction

qiwi_dp = QiwiDispatcher()
wallet = QiwiWallet(api_access_token='token', phone_number='+phone number')

dp = Dispatcher(Bot('BOT TOKEN'))


@qiwi_dp.transaction_handler()
async def handle_transaction(t: Transaction, ctx: Context):
    """Handle transaction here"""


@dp.message_handler()
async def handle_message(msg: Message):
    await msg.answer(text='Hello world')


async def on_startup(dp: Dispatcher):
    await start_non_blocking_qiwi_api_polling(wallet, qiwi_dp)


if __name__ == '__main__':
    executor.start_polling(dp, on_startup=on_startup)

Example usage without global variables#

import logging
from typing import cast

from aiogram import Bot, Dispatcher, types

from glQiwiApi import QiwiWrapper
from glQiwiApi.core.event_fetching import executor
from glQiwiApi.core.event_fetching.dispatcher import QiwiDispatcher
from glQiwiApi.core.event_fetching.executor import Context
from glQiwiApi.plugins import AiogramPollingPlugin
from glQiwiApi.qiwi.clients.wallet.types import Transaction

api_access_token = 'token'
phone_number = '+phone number'

logger = logging.getLogger(__name__)


async def aiogram_message_handler(msg: types.Message):
    await msg.answer(text='Привет😇')


async def qiwi_transaction_handler(update: Transaction, ctx: Context):
    print(update)


def on_startup(ctx: Context) -> None:
    logger.info('This message logged on startup')
    register_handlers(ctx)


def register_handlers(ctx: Context):
    ctx['qiwi_dp'].transaction_handler()(qiwi_transaction_handler)
    dispatcher = cast(Dispatcher, ctx['dp'])
    dispatcher.register_message_handler(aiogram_message_handler)


def run_application() -> None:
    logging.basicConfig(level=logging.INFO)
    bot = Bot('BOT TOKEN')
    dp = Dispatcher(bot)
    wallet = QiwiWrapper(api_access_token=api_access_token, phone_number=phone_number)
    qiwi_dp = QiwiDispatcher()

    executor.start_polling(
        wallet,
        qiwi_dp,
        AiogramPollingPlugin(dp),
        on_startup=on_startup,
        skip_updates=True,
        context={'dp': dp, 'qiwi_dp': qiwi_dp},
    )


if __name__ == '__main__':
    run_application()

Webhooks#

Quick example:

import logging

from aiogram import Bot, Dispatcher
from aiogram.dispatcher.webhook import configure_app
from aiohttp import web

from glQiwiApi import QiwiWallet
from glQiwiApi.core.event_fetching.dispatcher import QiwiDispatcher
from glQiwiApi.core.event_fetching.executor import Context, configure_app_for_qiwi_webhooks
from glQiwiApi.core.event_fetching.webhooks.config import (
    EncryptionConfig,
    HookRegistrationConfig,
    WebhookConfig,
)
from glQiwiApi.qiwi.clients.p2p.types import BillWebhook

qiwi_dp = QiwiDispatcher()

dp = Dispatcher(Bot('BOT TOKEN'))
wallet = QiwiWallet(api_access_token='wallet api token')


@qiwi_dp.bill_handler()
async def handle_webhook(webhook: BillWebhook, ctx: Context):
    # handle bill
    bill = webhook.bill


app = web.Application()
configure_app(
    dp,
    configure_app_for_qiwi_webhooks(
        wallet,
        qiwi_dp,
        app,
        WebhookConfig(
            encryption=EncryptionConfig(
                secret_p2p_key='secret p2p token, который был зарегистрирован с указанием айпи. '
                'Например http://айпи:8080/webhooks/qiwi/bills/'
            ),
            hook_registration=HookRegistrationConfig(host_or_ip_address='айпи:8080'),
        ),
    ),
    '/bot',
)

logging.basicConfig(level=logging.DEBUG)

if __name__ == '__main__':
    # Порт может быть любым
    web.run_app(app, port=8080)

Low level API features#

Query caching#

glQiwiApi provides builtin cache storage and cache invalidation strategies such a InMemoryCacheStorage and APIResponsesCacheInvalidationStrategy accordingly. Obviously, you can extend functionality of library and add, for example, Redis based cache storage.

Tip

By default InMemoryCacheStorage use UnrealizedCacheInvalidationStrategy as an invalidation strategy

Straightforward example#

import asyncio

from glQiwiApi.core.cache import InMemoryCacheStorage

storage = InMemoryCacheStorage()  # here is UnrealizedCacheInvalidationStrategy as an invalidation strategy


async def cache():
    await storage.update(cached=5)
    cached = await storage.retrieve("cached")
    print(f"You have cached {cached}")


asyncio.run(cache())

Advanced usage#

This very cache invalidation by timer strategy is worth using if you want to achieve cache invalidation. It should be noted that previous UnrealizedCacheInvalidationStrategy just ignores the invalidation and don’t get rid of aged cache.

import asyncio

from glQiwiApi.core.cache import InMemoryCacheStorage, CacheInvalidationByTimerStrategy

storage = InMemoryCacheStorage(CacheInvalidationByTimerStrategy(cache_time_in_seconds=1))


async def main():
    await storage.update(x=5)

    await asyncio.sleep(1)

    value = await storage.retrieve("x")  # None


asyncio.run(main())

Using proxy#

In the example below we’ll use aiohttp-socks library to establish socks5 proxy:

import asyncio

from aiohttp_socks import ProxyConnector

from glQiwiApi import QiwiWallet
from glQiwiApi.core import RequestService
from glQiwiApi.core.session import AiohttpSessionHolder


def create_request_service_with_proxy(w: QiwiWallet):
    return RequestService(
        session_holder=AiohttpSessionHolder(
            connector=ProxyConnector.from_url("socks5://34.134.60.185:443"),  # some proxy
            headers={
                "Content-Type": "application/json",
                "Accept": "application/json",
                "Authorization": f"Bearer {w._api_access_token}",
                "Host": "edge.qiwi.com",
            },
        )
    )


wallet = QiwiWallet(
    api_access_token="your token",
    phone_number="+phone number",
    request_service_factory=create_request_service_with_proxy,
)


async def main():
    async with wallet:
        print(await wallet.get_balance())


asyncio.run(main())

Known issues:#

` aiohttp.client_exceptions.ClientConnectorError: Cannot connect to api.qiwi.com ssl:true... `

This exception can be fixed this way:

import glQiwiApi
from glQiwiApi import QiwiWallet
from glQiwiApi.core import RequestService
from glQiwiApi.core.session import AiohttpSessionHolder


async def create_request_service(w: QiwiWallet):
    return RequestService(
        session_holder=AiohttpSessionHolder(
            headers={
                "Content-Type": "application/json",
                "Accept": "application/json",
                "Authorization": f"Bearer {w._api_access_token}",
                "Host": "edge.qiwi.com",
                "User-Agent": f"glQiwiApi/{glQiwiApi.__version__}",
            },
            trust_env=True
        )
    )


wallet = QiwiWallet(request_service_factory=create_request_service)

Types#

Qiwi types#

class glQiwiApi.qiwi.clients.wallet.types.Balance(*, alias: str, title: str, fsAlias: str, bankAlias: str, hasBalance: bool, balance: Optional[glQiwiApi.types.amount.AmountWithCurrency] = None, currency: glQiwiApi.types.amount.CurrencyModel, type: Optional[Dict[str, Any]] = None, defaultAccount: bool)[source]#

object: Balance

class glQiwiApi.qiwi.clients.wallet.types.CrossRate(*, to: Union[str, glQiwiApi.types.amount.CurrencyModel], rate: float, **extra_data: Any)[source]#

Курс валюты

class glQiwiApi.qiwi.clients.wallet.types.Identification(*, id: int, firstName: str, middleName: str, lastName: str, birthDate: datetime.date, passport: str, inn: Optional[str] = None, snils: Optional[str] = None, oms: Optional[str] = None, type: str)[source]#

object: Identification

class glQiwiApi.qiwi.clients.wallet.types.Limit(*, currency: glQiwiApi.types.amount.CurrencyModel, rest: Union[float, int], max: Union[float, int], spent: Union[float, int], interval: glQiwiApi.qiwi.clients.wallet.types.limit.Interval, type: str)[source]#

object: Limit

class glQiwiApi.qiwi.clients.wallet.types.Partner(*, title: str, id: int, maps: Optional[List[str]] = None)[source]#

Base partner class

class glQiwiApi.qiwi.clients.wallet.types.PaymentDetails(*, name: str, extra_to_bik: str, to_bik: str, city: str, info: str = 'Коммерческие организации', is_commercial: str = '1', to_name: str, to_inn: str, to_kpp: str, nds: str, goal: str, urgent: str = '0', account: str, from_name: str, from_name_p: str, from_name_f: str, requestProtocol: str = 'qw1', toServiceId: str = '1717')[source]#

Набор реквизитов платежа

account: str#

Номер счета получателя

city: str#

Город местонахождения получателя

extra_to_bik: str#

БИК банка получателя

from_name: str#

Имя плательщика

from_name_f: str#

Фамилия плательщика

from_name_p: str#

Отчество плательщика

goal: str#

Назначение платежа

info: str#

Константное значение

is_commercial: str#

Служебная информация

name: str#

Наименование банка получателя

nds: str#

Признак уплаты НДС. Если вы оплачиваете квитанцию и в ней не указан НДС, то строка НДС не облагается. В ином случае, строка В т.ч. НДС

requestProtocol: str#

Служебная информация, константа

toServiceId: str#

Служебная информация, константа

to_bik: str#

БИК банка получателя

to_inn: str#

ИНН организации

to_kpp: str#

КПП организации

to_name: str#

Наименование организации

urgent: str#

Признак срочного платежа (0 - нет, 1 - да). Срочный платеж выполняется от 10 минут. Возможен по будням с 9:00 до 20:30 по московскому времени. Стоимость услуги — 25 рублей.

class glQiwiApi.qiwi.clients.wallet.types.PaymentInfo(*, id: int, sum: glQiwiApi.types.amount.AmountWithCurrency, terms: str, fields: glQiwiApi.qiwi.clients.wallet.types.payment_info.Fields, source: str, transaction: Optional[glQiwiApi.qiwi.clients.wallet.types.payment_info.TransactionInfo] = None, comment: Optional[str] = None)[source]#

object: PaymentInfo

class glQiwiApi.qiwi.clients.wallet.types.Source(value)[source]#

An enumeration.

class glQiwiApi.qiwi.clients.wallet.types.Statistic(*, incomingTotal: List[glQiwiApi.types.amount.AmountWithCurrency], outgoingTotal: List[glQiwiApi.types.amount.AmountWithCurrency])[source]#

object: Statistic

class glQiwiApi.qiwi.clients.wallet.types.Transaction(*, txnId: int, personId: int, date: datetime.datetime, status: glQiwiApi.qiwi.clients.wallet.types.transaction.TransactionStatus, type: glQiwiApi.qiwi.clients.wallet.types.transaction.TransactionType, statusText: str, trmTxnId: str, account: str, sum: glQiwiApi.types.amount.AmountWithCurrency, commission: glQiwiApi.types.amount.AmountWithCurrency, total: glQiwiApi.types.amount.AmountWithCurrency, provider: glQiwiApi.qiwi.clients.wallet.types.transaction.Provider, source: Optional[glQiwiApi.qiwi.clients.wallet.types.transaction.Provider] = None, comment: Optional[str] = None, currencyRate: int)[source]#

object: Transaction

comment: Optional[str]#

Комментарий к платежу

commission: glQiwiApi.types.amount.AmountWithCurrency#

Данные о комиссии

currency_rate: int#

Курс конвертации (если применяется в транзакции)

date: datetime.datetime#

Для запросов истории платежей - Дата/время платежа, во временной зоне запроса (см. параметр startDate). Для запросов данных о транзакции - Дата/время платежа, время московское

id: int#

ID транзакции в сервисе QIWI Кошелек

person_id: int#

Номер кошелька

provider: glQiwiApi.qiwi.clients.wallet.types.transaction.Provider#

Данные о провайдере.

source: Optional[glQiwiApi.qiwi.clients.wallet.types.transaction.Provider]#

Служебная информация

status: glQiwiApi.qiwi.clients.wallet.types.transaction.TransactionStatus#

Статус платежа. Возможные значения: WAITING - платеж проводится, SUCCESS - успешный платеж, ERROR - ошибка платежа.

status_text: str#

Текстовое описание статуса платежа

sum: glQiwiApi.types.amount.AmountWithCurrency#

Данные о сумме платежа или пополнения.

to_account: str#

Для платежей - номер счета получателя. Для пополнений - номер отправителя, терминала или название агента пополнения кошелька

total: glQiwiApi.types.amount.AmountWithCurrency#

Общие данные о платеже в формате объекта Sum

trm_transaction_id: str#

Клиентский ID транзакции

type: glQiwiApi.qiwi.clients.wallet.types.transaction.TransactionType#

Тип платежа. Возможные значения: IN - пополнение, OUT - платеж, QIWI_CARD - платеж с карт QIWI (QVC, QVP).

class glQiwiApi.qiwi.clients.wallet.types.TransactionStatus(value)[source]#

An enumeration.

class glQiwiApi.qiwi.clients.wallet.types.TransactionType(value)[source]#

An enumeration.

class glQiwiApi.qiwi.clients.wallet.types.TransactionWebhook(*, hash: Optional[str] = None, hookId: str, messageId: Optional[str] = None, test: bool, version: str, payment: Optional[glQiwiApi.qiwi.clients.wallet.types.webhooks.WebhookPayment] = None, signature: Optional[str] = None)[source]#

Object: TransactionWebhook

signature: Optional[str]#

NOT API field, it’s generating by method _webhook_signature_collector Don’t rely on it, if you want to use signature, generate new one using the same logic as in validator

class glQiwiApi.qiwi.clients.p2p.types.RefundedBill(*, amount: glQiwiApi.types.amount.PlainAmount, datetime: datetime.datetime, refundId: str, status: str)[source]#

object: RefundedBill

YooMoney types#

Custom(arbitrary) types#

Note

When you use method QiwiWallet.get_receipt it returns a custom type File, that helps you to save receipt or get raw bytes

class glQiwiApi.types.arbitrary.file.File(input: glQiwiApi.types.arbitrary.inputs.AbstractInput[Any])[source]#
class glQiwiApi.types.arbitrary.inputs.AbstractInput(input_: glQiwiApi.types.arbitrary.inputs.InputType)[source]#
class glQiwiApi.types.arbitrary.inputs.BinaryIOInput(input_: glQiwiApi.types.arbitrary.inputs.InputType)[source]#
class glQiwiApi.types.arbitrary.inputs.PathlibPathInput(input_: glQiwiApi.types.arbitrary.inputs.InputType)[source]#
class glQiwiApi.types.arbitrary.inputs.PlainPathInput(input_: glQiwiApi.types.arbitrary.inputs.InputType)[source]#