pennylane-sdk-php¶
The unofficial PHP 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. A Python sibling SDK covers the same API with the same design contracts, if that fits your stack better.
Why this SDK¶
- Complete: all 213 operations of the Company API v2 and the Firm API v1 are implemented. Coverage is measured against the official OpenAPI specs by an audit script that runs in CI.
- Typed: every response is a readonly PHP object, hydrated defensively so unknown or newly added API fields never break your code.
- Money as strings: monetary amounts and quantities travel as numeric strings, never floats, matching the API contract and avoiding rounding errors on accounting data.
- 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¶
composer require goatandcow7/pennylane-sdk
Requires PHP 8.2 or newer. The SDK talks to the API through PSR-18, so it needs an HTTP client. Guzzle is suggested and auto-detected through php-http/discovery:
composer require guzzlehttp/guzzle
php-http/discovery runs as a Composer plugin; allow it once in composer.json:
"config": {
"allow-plugins": {
"php-http/discovery": true
}
}
A taste¶
<?php
use Pennylane\Sdk\Pennylane;
use Pennylane\Sdk\Filter;
$client = new Pennylane(); // reads PENNYLANE_API_TOKEN
// Walk through every invoice since January, newest first
foreach ($client->customerInvoices->list(
filter: [Filter::gte('date', '2026-01-01')],
sort: '-date',
) as $invoice) {
echo $invoice->invoiceNumber . ' ' . $invoice->currencyAmount . PHP_EOL;
}
// Create and finalize an invoice
$invoice = $client->customerInvoices->create(
date: '2026-07-08',
deadline: '2026-08-07',
customerId: 123,
invoiceLines: [['product_id' => 45, 'quantity' => '2']],
);
$client->customerInvoices->finalize($invoice->id);
$client->customerInvoices->sendByEmail($invoice->id);
Accounting firms can operate across their whole portfolio:
<?php
use Pennylane\Sdk\PennylaneFirm;
$firm = new PennylaneFirm(); // reads PENNYLANE_FIRM_API_TOKEN
foreach ($firm->companies->list() as $company) {
$balance = $firm->trialBalance->list(
$company->id,
periodStart: '2026-01-01',
periodEnd: '2026-06-30',
);
}
Where to go next¶
- Getting started: tokens, first call, error handling basics.
- Guides: authentication, pagination, error handling and retries.