Invoicing (sales)¶
This page covers the customer-facing side of the Company API: customers, quotes, customer invoices and credit notes, recurring billing subscriptions, read only commercial documents, invoice templates, and the product catalog used to fill invoice and quote lines.
Customers ($client->customers)¶
Reads customers regardless of kind (company or individual) and manages their categories and
contacts. This resource wires two sub resources, ->companies and ->individuals, which you
use to create or update a customer of a specific kind.
| Method | HTTP | Scope | Description |
|---|---|---|---|
list($cursor = null, $limit = null, ...) |
GET /customers |
customers:all, customers:readonly |
List customers, company and individual alike. |
get($customerId) |
GET /customers/{customerId} |
customers:all, customers:readonly |
Retrieve a customer by its identifier, company or individual alike. |
listCategories($customerId, $cursor = null, $limit = null) |
GET /customers/{customerId}/categories |
customers:readonly, customers:all |
List the categories assigned to a customer. |
categorize($customerId, $categories) |
PUT /customers/{customerId}/categories |
customers:all |
Replace the categories assigned to a customer with the given list. |
listContacts($customerId, $cursor = null, $limit = null, $sort = null) |
GET /customers/{customerId}/contacts |
customers:all, customers:readonly |
List the contacts of a customer. |
CompanyCustomers ($client->customers->companies)¶
Creates and manages customers that are companies (as opposed to individuals).
| Method | HTTP | Scope | Description |
|---|---|---|---|
create($name, $billingAddress, $vatNumber = null, ...) |
POST /company_customers |
customers:all |
Create a company customer. |
get($companyCustomerId) |
GET /company_customers/{companyCustomerId} |
customers:all, customers:readonly |
Retrieve a company customer by its identifier. |
update($companyCustomerId, $name = null, ...) |
PUT /company_customers/{companyCustomerId} |
customers:all |
Update a company customer. |
IndividualCustomers ($client->customers->individuals)¶
Creates and manages customers that are individuals (as opposed to companies).
| Method | HTTP | Scope | Description |
|---|---|---|---|
create($firstName, $lastName, $billingAddress, $phone = null, ...) |
POST /individual_customers |
customers:all |
Create an individual customer. |
get($individualCustomerId) |
GET /individual_customers/{individualCustomerId} |
customers:all, customers:readonly |
Retrieve an individual customer by its identifier. |
update($individualCustomerId, $firstName = null, ...) |
PUT /individual_customers/{individualCustomerId} |
customers:all |
Update an individual customer. |
CustomerInvoices ($client->customerInvoices)¶
Manages customer invoices end to end: draft and finalized invoices, credit notes, e-invoicing imports, categorization, appendices, and reconciliation with bank transactions and payments.
| Method | HTTP | Scope | Description |
|---|---|---|---|
list($cursor = null, $limit = null, ...) |
GET /customer_invoices |
customer_invoices:all or customer_invoices:readonly |
List customer invoices. |
create($date, $deadline, $customerId, $invoiceLines, $draft = true, ...) |
POST /customer_invoices |
customer_invoices:all |
Create a customer invoice, as a draft or finalized directly. |
get($customerInvoiceId) |
GET /customer_invoices/{customerInvoiceId} |
customer_invoices:all or customer_invoices:readonly |
Retrieve a customer invoice by its identifier. |
update($customerInvoiceId, $date = null, ...) |
PUT /customer_invoices/{customerInvoiceId} |
customer_invoices:all |
Update a customer invoice (draft invoices accept more fields than finalized ones). |
delete($customerInvoiceId) |
DELETE /customer_invoices/{customerInvoiceId} |
customer_invoices:all |
Delete a draft customer invoice (finalized invoices cannot be deleted). |
importFromFile($fileAttachmentId, $date, $deadline, $customerId, $currencyAmountBeforeTax, $currencyAmount, $currencyTax, $invoiceLines, $importAsIncomplete = null, ...) |
POST /customer_invoices/import |
customer_invoices:all |
Import a customer invoice from a file already uploaded through file attachments. |
importEInvoice($file, $invoiceOptions = null) |
POST /customer_invoices/e_invoices/imports |
customer_invoices:all |
Import a Factur-X, UBL or CII e-invoice file; the invoice is built asynchronously. |
createFromQuote($quoteId, $draft, $externalReference = null, $customerInvoiceTemplateId = null) |
POST /customer_invoices/create_from_quote |
customer_invoices:all |
Create a customer invoice from an existing quote. |
sendToPa($customerInvoiceId) |
POST /customer_invoices/{customerInvoiceId}/send_to_pa |
customer_invoices:all |
Send a customer e-invoice to the Partner Agreed (PA) platform. |
finalize($customerInvoiceId) |
PUT /customer_invoices/{customerInvoiceId}/finalize |
customer_invoices:all |
Turn a draft invoice into a finalized invoice. |
markAsPaid($customerInvoiceId) |
PUT /customer_invoices/{customerInvoiceId}/mark_as_paid |
customer_invoices:all |
Mark a customer invoice as paid. |
sendByEmail($customerInvoiceId, $recipients = null) |
POST /customer_invoices/{customerInvoiceId}/send_by_email |
customer_invoices:all |
Send a customer invoice by email. |
linkCreditNote($customerInvoiceId, $creditNoteId) |
POST /customer_invoices/{customerInvoiceId}/link_credit_note |
customer_invoices:all |
Link a credit note to a customer invoice. |
updateImported($customerInvoiceId, $date = null, ...) |
PUT /customer_invoices/{customerInvoiceId}/update_imported |
customer_invoices:all |
Update an imported customer invoice. |
listInvoiceLines($customerInvoiceId, $cursor = null, $limit = null, $sort = null) |
GET /customer_invoices/{customerInvoiceId}/invoice_lines |
customer_invoices:all or customer_invoices:readonly |
List invoice lines for a customer invoice. |
listInvoiceLineSections($customerInvoiceId, $cursor = null, $limit = null, $sort = null) |
GET /customer_invoices/{customerInvoiceId}/invoice_line_sections |
customer_invoices:all or customer_invoices:readonly |
List invoice line sections for a customer invoice. |
listPayments($customerInvoiceId, $cursor = null, $limit = null, $sort = null) |
GET /customer_invoices/{customerInvoiceId}/payments |
customer_invoices:all or customer_invoices:readonly |
List payments recorded against a customer invoice. |
listMatchedTransactions($customerInvoiceId, $cursor = null, $limit = null, $sort = null) |
GET /customer_invoices/{customerInvoiceId}/matched_transactions |
customer_invoices:all or customer_invoices:readonly |
List bank transactions matched to a customer invoice. |
matchTransaction($customerInvoiceId, $transactionId) |
POST /customer_invoices/{customerInvoiceId}/matched_transactions |
customer_invoices:all |
Match a bank transaction to a customer invoice. |
unmatchTransaction($customerInvoiceId, $transactionId) |
DELETE /customer_invoices/{customerInvoiceId}/matched_transactions/{transactionId} |
customer_invoices:all |
Unmatch a bank transaction from a customer invoice. |
listAppendices($customerInvoiceId, $cursor = null, $limit = null) |
GET /customer_invoices/{customerInvoiceId}/appendices |
customer_invoices:all or customer_invoices:readonly |
List appendices attached to a customer invoice. |
addAppendix($customerInvoiceId, $file) |
POST /customer_invoices/{customerInvoiceId}/appendices |
customer_invoices:all |
Upload an appendix file (a supporting document) for a customer invoice. |
listCategories($customerInvoiceId, $cursor = null, $limit = null) |
GET /customer_invoices/{customerInvoiceId}/categories |
customer_invoices:all or customer_invoices:readonly |
List categories assigned to a customer invoice. |
categorize($customerInvoiceId, $categories) |
PUT /customer_invoices/{customerInvoiceId}/categories |
customer_invoices:all |
Replace the categories assigned to a customer invoice. |
listCustomHeaderFields($customerInvoiceId, $cursor = null, $limit = null, $sort = null) |
GET /customer_invoices/{customerInvoiceId}/custom_header_fields |
customer_invoices:all or customer_invoices:readonly |
List custom header fields for a customer invoice. |
CustomerInvoiceTemplates ($client->customerInvoiceTemplates)¶
Read only access to the customer invoice templates configured on the company (used to brand and structure generated invoice PDFs).
| Method | HTTP | Scope | Description |
|---|---|---|---|
list($cursor = null, $limit = null, $sort = null) |
GET /customer_invoice_templates |
customer_invoice_templates:readonly |
List customer invoice templates configured on the company. |
Quotes ($client->quotes)¶
Manages quotes sent to customers, including their lines, sections, appendices and status transitions.
| Method | HTTP | Scope | Description |
|---|---|---|---|
list($cursor = null, $limit = null, ...) |
GET /quotes |
quotes:all, quotes:readonly |
List quotes. |
create($date, $deadline, $customerId, $invoiceLines, $quoteTemplateId = null, ...) |
POST /quotes |
quotes:all |
Create a quote. |
get($quoteId) |
GET /quotes/{quoteId} |
quotes:all, quotes:readonly |
Retrieve a quote by its identifier. |
update($quoteId, $date = null, ...) |
PUT /quotes/{quoteId} |
quotes:all |
Update a quote. |
listAppendices($quoteId, $cursor = null, $limit = null) |
GET /quotes/{quoteId}/appendices |
quotes:all, quotes:readonly |
List the appendices (attached files) of a quote. |
addAppendix($quoteId, $file) |
POST /quotes/{quoteId}/appendices |
quotes:all |
Upload an appendix for a quote. |
listInvoiceLines($quoteId, $cursor = null, $limit = null, $sort = null) |
GET /quotes/{quoteId}/invoice_lines |
quotes:all, quotes:readonly |
List the invoice lines of a quote. |
listInvoiceLineSections($quoteId, $cursor = null, $limit = null, $sort = null) |
GET /quotes/{quoteId}/invoice_line_sections |
quotes:all, quotes:readonly |
List the invoice line sections of a quote. |
sendByEmail($quoteId, $recipients = null) |
POST /quotes/{quoteId}/send_by_email |
quotes:all |
Send a quote by email. |
updateStatus($quoteId, $status) |
PUT /quotes/{quoteId}/update_status |
quotes:all |
Update the status of a quote (pending, accepted, denied, invoiced, or expired). |
CommercialDocuments ($client->commercialDocuments)¶
Read only access to commercial documents: proformas, shipping orders and purchasing orders. These are generated from quotes or created directly in the Pennylane app; there is no create, update or delete operation.
| Method | HTTP | Scope | Description |
|---|---|---|---|
list($cursor = null, $limit = null, ...) |
GET /commercial_documents |
commercial_documents:all, commercial_documents:readonly |
List commercial documents. |
get($commercialDocumentId) |
GET /commercial_documents/{commercialDocumentId} |
commercial_documents:all, commercial_documents:readonly |
Retrieve a commercial document by its identifier. |
listAppendices($commercialDocumentId, $cursor = null, $limit = null) |
GET /commercial_documents/{commercialDocumentId}/appendices |
commercial_documents:all, commercial_documents:readonly |
List the appendices (attached files) of a commercial document. |
addAppendix($commercialDocumentId, $file) |
POST /commercial_documents/{commercialDocumentId}/appendices |
commercial_documents:all |
Upload an appendix for a commercial document. |
listInvoiceLines($commercialDocumentId, $cursor = null, $limit = null, $sort = null) |
GET /commercial_documents/{commercialDocumentId}/invoice_lines |
commercial_documents:all, commercial_documents:readonly |
List the invoice lines of a commercial document. |
listInvoiceLineSections($commercialDocumentId, $cursor = null, $limit = null, $sort = null) |
GET /commercial_documents/{commercialDocumentId}/invoice_line_sections |
commercial_documents:all, commercial_documents:readonly |
List the invoice line sections of a commercial document. |
BillingSubscriptions ($client->billingSubscriptions)¶
Creates and manages recurring billing subscriptions that automatically generate customer invoices on a schedule (yearly, monthly or weekly).
| Method | HTTP | Scope | Description |
|---|---|---|---|
list($cursor = null, $limit = null, ...) |
GET /billing_subscriptions |
billing_subscriptions:all, billing_subscriptions:readonly |
List billing subscriptions. |
create($start, $mode, $paymentConditions, $paymentMethod, $recurringRule, $customerId, $customerInvoiceData, $label = null) |
POST /billing_subscriptions |
billing_subscriptions:all |
Create a billing subscription that generates customer invoices on a recurring schedule. |
get($billingSubscriptionId) |
GET /billing_subscriptions/{billingSubscriptionId} |
billing_subscriptions:all, billing_subscriptions:readonly |
Retrieve a billing subscription by its identifier. |
update($billingSubscriptionId, $stop = null, ...) |
PUT /billing_subscriptions/{billingSubscriptionId} |
billing_subscriptions:all |
Update a billing subscription, including pausing or resuming it. |
listInvoiceLineSections($billingSubscriptionId, $cursor = null, $limit = null, $sort = null) |
GET /billing_subscriptions/{billingSubscriptionId}/invoice_line_sections |
billing_subscriptions:all, billing_subscriptions:readonly |
List the invoice line sections of a billing subscription. |
listInvoiceLines($billingSubscriptionId, $cursor = null, $limit = null, $sort = null) |
GET /billing_subscriptions/{billingSubscriptionId}/invoice_lines |
billing_subscriptions:all, billing_subscriptions:readonly |
List the invoice lines of a billing subscription. |
Products ($client->products)¶
Manages the product catalog used to fill invoice, quote and billing subscription lines.
| Method | HTTP | Scope | Description |
|---|---|---|---|
list($cursor = null, $limit = null, ...) |
GET /products |
products:readonly |
List products. |
create($label, $priceBeforeTax, $vatRate, $description = null, ...) |
POST /products |
products:all |
Create a product. |
get($productId) |
GET /products/{productId} |
products:readonly |
Retrieve a product by its identifier. |
update($productId, $label = null, ...) |
PUT /products/{productId} |
products:all |
Update a product. |
Example¶
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use Pennylane\Sdk\Pennylane;
use Pennylane\Sdk\Filter;
$client = new Pennylane();
// Create a company customer.
$customer = $client->customers->companies->create(
name: 'Acme Corp',
billingAddress: [
'address' => '12 rue de Rivoli',
'postal_code' => '75004',
'city' => 'Paris',
'country_alpha2' => 'FR',
],
);
// Add a product to the catalog.
$product = $client->products->create(
label: 'Consulting (half day)',
priceBeforeTax: '450.00',
vatRate: 'FR_200',
);
// Draft an invoice for that customer using the product, then finalize it.
$invoice = $client->customerInvoices->create(
date: '2026-07-09',
deadline: '2026-08-08',
customerId: $customer->id,
invoiceLines: [
['product_id' => $product->id, 'quantity' => '2'],
],
);
$finalized = $client->customerInvoices->finalize($invoice->id);
// List invoices created this month.
foreach ($client->customerInvoices->list(filter: Filter::gte('date', '2026-07-01')) as $inv) {
echo $inv->id, "\n";
}