Skip to content

Unofficial and async Python module to interface with the payment processor Payconiq.

License

Notifications You must be signed in to change notification settings

peinser/pyconiq

Repository files navigation


Unofficial async Python module to interface with the payment processor Payconiq.

Introduction

Warning

This is an initial PoC and integration of the module. The API will most likely change in future releases.

Installation

The module can be directly installed through pip:

pip install pyconiq

For development purposes, and once the project cloned or the codespace ready, you can install the project dependencies. You can use the dev extra to install the development dependencies.

poetry install --with=dev

Or using pip:

pip install -e .[dev]

Getting started

Before you can integrate your application with Payconiq, you need access to a so-called Merchant profile. The process of onboarding with Payconiq, both for their development (EXT) and production (PROD) environment involves opening a support ticket (e-mail) and exchanging some information to setup your account. In particular, your mobile phone number, address, Tax ID (if availablef), and company name amongst others. The onboarding procedure is outlined here.

Important

You will have to provide a default callback URL to the support team that Payconiq will use to send updates regarding payment requests and transactions.

Once onboarded by the support team, you'll most likely have access to the EXT infrastructure. This means you have access to the necessary API keys and unique merchant identifier. In the wild, the most common integration a consumer will experience (we think) is the Static QR code integration. This QR code is uniquely tied to a specific Point of Sale (PoS) of a merchant. Meaning, a Point of Sale is uniquely identified by the tuple (Merchant ID and PoS ID), the latter is in your control.

Environment variables

pyconiq supports to inject several runtime defaults through environment variables. This is especially useful when targetting the EXT infrastructure compared to the default PROD infrastructure.

Variable Default Context
PYCONIQ_BASE https://payconiq.com Base endpoint of Payconiq.com.
PYCONIQ_API_BASE https://api.payconiq.com The primary API endpoint of Payconiq (or some mock service). By default this variable will target the Payconiq production environment. For the EXT environment this variable should be set to https://api.ext.payconiq.com. Note that setting this environment variable is not necessary. It can be defined in the codebase when allocating specific integrations.
PYCONIQ_DEFAULT_MERCHANT None Default Merchant ID that will be used when allocating merchants.
PYCONIQ_API_KEY_STATIC None Default API key for the Static QR code integration.
PYCONIQ_API_KEY_INVOICE None Default API key for the Invoice integration whenever no key is manually specified.
PYCONIQ_API_KEY_RECEIPT None Default API key for the Receipt integration whenever no key is manually specified.
PYCONIQ_API_KEY_APP2APP None Default API key for the App2App integration whenever no key is manually specified.
PYCONIQ_PAYMENT_PROFILE_STATIC None Payment profile identifier of the Static QR code integration

Example

First, before you use the Static QR integration, you need a QR code for your customers to scan. You can obtain this QR code through Payconiq's API. However, pyconiq provides a utility to generate this on the fly for you, with various error correction levels and customization options. This functionality is powered by the awesome qrcode module.

Tip

Note, the default merchant identifier and the default payment profile for the static can be set through the PYCONIQ_DEFAULT_MERCHANT and PYCONIQ_PAYMENT_PROFILE_STATIC environment variables respectively.

import pyconiq.qr

# Assign a unique identifier to your point of sale.
# This is managed by us, the merchant.
point_of_sale_id = "test"

# Set your merchant configuration, this will implicetly use the
# `PYCONIQ_DEFAULT_MERCHANT` environment variable for populating
# the merchant identifier.
merchant = pyconiq.merchant()

# Alternatively, the merchant can be generated as.
merchant = pyconiq.merchant(merchant_id="YourMerchantIdentifier")

integration = StaticIntegration(merchant=merchant, profile="YourPaymentProfileId)

# Second, we need a QR code that is associated with our PoS (point of sale).
# In this case, the identifier of the PoS is `test`.
qr = pyconiq.qr.static(integration=integration, pos=point_of_sale_id)
# Show the QR code in the terminal.
qr.print_ascii(tty=True)

this produces the following QR code (in your terminal) for our test Merchant;

█▀▀▀▀▀▀▀██▀██▀█▀███▀█▀█▀▀▀▀▀▀▀█
█ █▀▀▀█ █▀▀ ▄ █▀ ▄███▀█ █▀▀▀█ █
█ █   █ ██▄ ▄█▄ ██▄  ▄█ █   █ █
█ ▀▀▀▀▀ █▀▄▀█▀▄▀▄▀▄▀▄▀█ ▀▀▀▀▀ █
█▀▀▀█▀▀▀▀ ▄ ▀▄▄▀▀█ ▄ █▀▀███▀███
███▄▀ ▀▀▀█▀▄▄█▀██ █ ▄▄▄▄█▄██ ▀█
█▄▀   ▄▀█ ██▄▀██▄ ▄▀ ▀▄█▀█ █▀▀█
████▄█▀▀█▄▄▀  ▄▀█▀█   ▀███▀   █
█  █▀▀▄▀▄▀▀▀▀▄▄ ▀▄█▀ ▄▀█▄█▀ ▄▄█
█▀▄▀█▀█▀▀▀  ▄█▀▄▄  █▄█▄▄  █▀▄▄█
█▀▄▀  ▀▀▀▀ █▄▀██ █  ▄ ▀▀▀ ███▀█
█▀▀▀▀▀▀▀█ ▄▄  ▄▀▀ █▀█ █▀█ ▀▄█ █
█ █▀▀▀█ █ ▄▀▀▄▄ █▀▄█  ▀▀▀ █ █▄█
█ █   █ █▀ ▀▄█▀▄▄ █▄▀  ██ ▄▀█▀█
█ ▀▀▀▀▀ █ █▀▄▀██▀▀▄█▄██ █▀▀ ▄ █
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀

Once the QR code has been generated, we can now create payment requests (which we call transactions internally). Such requests are allocated through "Integrations". For this particular type, we're using a StaticIntegration, which corresponds to the integration supported the previously generated static QR code.

# Initiate a payment request with a static QR integration.
transaction = await integration.create(
  amount=2000,  # IMPORTANT: Amount is in Eurocent
  pos=point_of_sale_id,
  reference="PYCONIQ TEST",  # Reference that will appear as a reference in the bank log.
)

Tip

You can specify custom Callback URL's using the callback parameter when creating transactions.

At this point, the transaction has been allocated and is currently in a PENDING state. For the Static QR integration, transactions remain in a PENDING state for about 2 minutes before expiring. Updates regarding payment information will be provided through the callback URL. However, if you're simply testing locally, you can poll the status of the transaction like this:

#Just scan the QR code now.
while not transaction.terminal():  # Is the transaction in a `terminal` state?
  await asyncio.sleep(1)
  await transaction.update()

if transaction.expired():
  print("Failed to pay on time :(")
elif transaction.succeeded():
  print("Paid!")
elif transaction.cancelled():
  print("The transaction was cancelled!")
else:
  print("Some other status :/")

Important

The infrastructure supporting the External build is switched off each day from 21h30(CET) to 6h00 (CET) and during the weekends from Friday 21h30 (CET) until Monday 6h00 (CET).

Detailed information regarding the Payconiq's API specification can be found here.

Roadmap

Currently, only the Static QR code integration is supported. In the near future, we intent to support the Invoice integration.

About

Unofficial and async Python module to interface with the payment processor Payconiq.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

No packages published