Skip to main content

Async Python client for Qonto Business API

Project description

qodev-qonto-api

CI PyPI Python

Async Python client for Qonto Business API with full type safety.

Features

  • Async-first design built on httpx
  • Full Pydantic v2 models with extra="allow" for forward compatibility
  • Context manager support for clean resource management
  • Sandbox support via QONTO_BASE_URL environment variable or base_url= kwarg
  • ~40 API methods across 15+ resource types (organizations, memberships, labels, bank accounts, transactions, attachments, clients, invoices, quotes, credit notes, supplier invoices, products, SEPA transfers, bulk transfers, internal transfers, beneficiaries)
  • Multipart attachment upload helper for receipts and documents
  • Typed exceptionsAuthenticationError, NotFoundError, ValidationError, RateLimitError, APIError
  • Generic PaginatedResponse[T] with Qonto meta-envelope flattening
  • Rate-limit header tracking via client.rate_limit_status
  • py.typed marker for downstream type checking

Installation

pip install qodev-qonto-api

Or with uv:

uv add qodev-qonto-api

Quick Start

import asyncio
from qodev_qonto_api import QontoClient


async def main():
    async with QontoClient() as client:  # reads QONTO_LOGIN + QONTO_SECRET_KEY
        org = await client.get_organization()
        print(org.legal_name)

        accounts = await client.list_bank_accounts()
        for account in accounts:
            txns = await client.list_transactions(
                bank_account_id=account.id, per_page=10,
            )
            print(f"{account.iban}: {len(txns.items)} recent")


asyncio.run(main())

Configuration

Credentials

Set the two required environment variables:

export QONTO_LOGIN="your-org-login"
export QONTO_SECRET_KEY="your-secret-key"

Or pass directly:

async with QontoClient(login="your-org-login", secret_key="your-secret-key") as client:
    ...

Important: The Qonto Authorization header is the literal string {login}:{secret} with a real colon. This is not HTTP Basic Authentication — there is no Base64 encoding.

Sandbox

Switch to the staging sandbox via env var:

export QONTO_BASE_URL="https://thirdparty-sandbox.staging.qonto.co/v2"

Or via kwarg:

async with QontoClient(base_url="https://thirdparty-sandbox.staging.qonto.co/v2") as client:
    ...

Timeout

Customize request timeout (default 30 seconds):

async with QontoClient(timeout=60.0) as client:
    ...

Rate Limiting

Qonto enforces these limits (per IP):

  • 1,000 requests / 10 seconds
  • 10,000 requests / 10 minutes

Rate-limit headers are captured defensively (Qonto does not officially document header names — the client captures any ratelimit-* or x-ratelimit-* header) and exposed as a raw dict:

async with QontoClient() as client:
    await client.list_bank_accounts()
    print(client.rate_limit_status)  # {"x-ratelimit-remaining": "998", ...}

API Methods

Organization

org = await client.get_organization()

Memberships & Labels

members = await client.list_memberships()
labels = await client.list_labels()

Bank Accounts

accounts = await client.list_bank_accounts()

Transactions

GET /transactions requires either bank_account_id or iban:

txns = await client.list_transactions(bank_account_id="acc_123", per_page=50)
txn = await client.get_transaction("txn_456")

Attachments

attachment = await client.upload_attachment(
    file_path="invoice.pdf",
    idempotency_key="unique-key-123",
)
await client.attach_to_transaction(transaction_id="txn_456", attachment_ids=[attachment.id])

Clients

clients = await client.list_clients()
client_obj = await client.create_client(type="company", name="Acme Corp", email="billing@acme.com")

Client Invoices

invoices = await client.list_client_invoices()
invoice = await client.create_client_invoice(client_id="cl_1", items=[...])

Quotes & Credit Notes

quotes = await client.list_quotes()
credit_notes = await client.list_credit_notes()

Supplier Invoices

supplier_invoices = await client.list_supplier_invoices()
si = await client.get_supplier_invoice("si_123")

Products

products = await client.list_products()

SEPA Transfers

# VoP (Verification of Payee) must be called manually — pass the resulting
# vop_proof_token via extra_fields. See roadmap.
transfer = await client.create_sepa_transfer(
    debit_account_id="acc_1",
    beneficiary_id="ben_1",
    amount="100.00",
    currency="EUR",
    reference="Invoice INV-001",
    vop_proof_token="token-from-verify-payee",
)

Bulk Transfers & Internal Transfers

bulk = await client.create_bulk_transfer(debit_account_id="acc_1", transfers=[...])
internal = await client.create_internal_transfer(
    debit_account_id="acc_1",
    credit_account_id="acc_2",
    amount="50.00",
)

Beneficiaries

beneficiaries = await client.list_beneficiaries()

Error Handling

from qodev_qonto_api import (
    QontoClient,
    QontoError,
    AuthenticationError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    APIError,
)

try:
    async with QontoClient() as client:
        await client.get_transaction("does-not-exist")
except AuthenticationError:
    print("Invalid login / secret key")
except NotFoundError:
    print("Resource not found")
except ValidationError as e:
    for err in e.errors:
        print(f"{err.get('source', {}).get('pointer')}: {err.get('detail')}")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except APIError as e:
    print(f"API error: {e} (status: {e.status_code})")
except QontoError as e:
    print(f"Qonto client error: {e}")

Development

make install          # Install dependencies
make check            # Lint, format, typecheck, typos
make test             # Run tests with coverage

Roadmap (Out of Scope for v0.1.0)

  • OAuth2 / Qonto Connect — partner app integrations
  • PSD2 QSeal certificates — regulatory signing
  • Cards API — virtual/physical card management
  • Webhooks — event subscriptions
  • Onboarding API — account creation flows
  • VoP integration — Verification of Payee for SEPA transfers (currently manual via extra_fields)
  • Payment links
  • Embed iframe features

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qodev_qonto_api-0.1.0.tar.gz (65.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qodev_qonto_api-0.1.0-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

Details for the file qodev_qonto_api-0.1.0.tar.gz.

File metadata

  • Download URL: qodev_qonto_api-0.1.0.tar.gz
  • Upload date:
  • Size: 65.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qodev_qonto_api-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e1fbffffbdd16e4315c91b3436581b8a6fe52bc3d9f83b08b6615ad04ecbc3f1
MD5 b411489a7f0ef046d44a520e641c3324
BLAKE2b-256 b44276fd4bfa9a32ada2a8dc6e92987a557b7d3c1b2246084339dc605ea5d2e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for qodev_qonto_api-0.1.0.tar.gz:

Publisher: publish.yml on qodevai/qonto-api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file qodev_qonto_api-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for qodev_qonto_api-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9e6782de12f986abf69124f492df5ea14434dfbaa756147793895028a7adff92
MD5 9e8f1d2a7d2e87478ce687065f0ae9f5
BLAKE2b-256 3e96c2a9c009944dd64cb04bf89e4df7aa269bfa8f9dc4c8edce949f2c949167

See more details on using hashes here.

Provenance

The following attestation bundles were made for qodev_qonto_api-0.1.0-py3-none-any.whl:

Publisher: publish.yml on qodevai/qonto-api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page