Skip to content

pennylane-sdk

The unofficial Python SDK for the Pennylane API, the French accounting and invoicing platform used by tens of thousands of companies and accounting firms.

Not affiliated

This is a community project, not affiliated with Pennylane SAS. It is also unrelated to the PennyLane quantum computing framework, which owns the pennylane name on PyPI. This package is pennylane-sdk.

Why this SDK

  • Complete: every operation of the Company API v2 (165 operations) and the Firm API v1 (48 operations) is implemented, in both sync and async flavors. Coverage is measured against the official OpenAPI specs by an audit script that runs in CI.
  • Typed: every response is a Pydantic model. Monetary amounts are Decimal, never floats, matching the API contract (amounts travel as strings to avoid rounding errors).
  • Safe for accounting data: the Pennylane API has no server-side idempotency, so the SDK never retries a POST after a server error. You will not create duplicate invoices because of a network hiccup.
  • Rate-limit aware: requests are paced client-side to the official limits (25 requests per 5 seconds for companies, 5 per second for firms), and 429 responses are retried honoring retry-after. Bulk exports just work.
  • Pagination that disappears: iterate over a list call and the SDK fetches the next pages for you, under the rate limit, re-sending your filters as the API requires.

Install

pip install pennylane-sdk

Requires Python 3.10+.

A taste

from decimal import Decimal
from pennylane_sdk import Pennylane, filters

client = Pennylane()  # reads PENNYLANE_API_TOKEN

# Walk through every invoice since January, newest first
for invoice in client.customer_invoices.list(
    filter=[filters.gte("date", "2026-01-01")],
    sort="-date",
):
    print(invoice.invoice_number, invoice.currency_amount)

# Create and finalize an invoice
invoice = client.customer_invoices.create(
    customer_id=123,
    date="2026-07-08",
    deadline="2026-08-07",
    invoice_lines=[{"product_id": 45, "quantity": "2"}],
)
client.customer_invoices.finalize(invoice.id)
client.customer_invoices.send_by_email(invoice.id)

Async version, same surface:

from pennylane_sdk import AsyncPennylane

async with AsyncPennylane() as client:
    page = await client.customer_invoices.list(limit=100)
    async for invoice in page:
        ...

Accounting firms can operate across their whole portfolio:

from pennylane_sdk import PennylaneFirm

firm = PennylaneFirm()  # reads PENNYLANE_FIRM_API_TOKEN
for company in firm.companies.list():
    balance = firm.trial_balance.list(
        company.id, period_start="2026-01-01", period_end="2026-06-30"
    )

Where to go next

  • Getting started: tokens, first call, sandbox.
  • Guides: authentication, pagination, error handling, invoicing lifecycle, the 2026 French e-invoicing reform, webhooks.
  • API reference: every resource and model, generated from the code.