Skip to content

Repository files navigation

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

About

Async Python client for Qonto Business API

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages