# Provenance: modeled-from-docs (2026-07-17) # Source: Pennylane Company API v2 developer documentation at https://pennylane.readme.io # - Endpoint list + operationIds: https://pennylane.readme.io/llms.txt and /reference/* # - Confirmed base URL from live reference example requests: https://app.pennylane.com/api/external/v2 # - Auth (Bearer token: Company API token, Firm API token, or OAuth 2.0 access token) # confirmed from https://pennylane.readme.io/docs/getting-started and /docs/oauth-20-walkthrough # No first-party OpenAPI/Swagger file is published for download; this document models the # documented REST surface. Paths and operationIds mirror the published API Reference; a # representative (not exhaustive) subset of Pennylane's ~150 v2 operations is included. openapi: 3.0.1 info: title: Pennylane Company API description: >- Pennylane is a French financial and accounting operating system for SMEs and accounting firms. The Company API (v2) lets companies, firms, and integration partners access and sync invoicing, accounting, banking, and financial data, and automate end-to-end workflows. V2 is the stable version; V1 is deprecated. termsOfService: https://pennylane.readme.io/docs/api-contract-terms contact: name: Pennylane API Support url: https://pennylane.readme.io/docs/how-to-reach-out-to-us version: '2.0' servers: - url: https://app.pennylane.com/api/external/v2 description: Production (v2) security: - bearerAuth: [] tags: - name: Account - name: Journals - name: Ledger Accounts - name: Ledger Entries - name: Accounting Exports - name: Categories - name: Customer Invoices - name: Supplier Invoices - name: Quotes - name: Billing Subscriptions - name: Products - name: Customers - name: Suppliers - name: Bank Accounts - name: Transactions - name: Mandates - name: File Attachments - name: Change Events - name: E-Invoicing paths: /me: get: operationId: getMe tags: [Account] summary: User profile description: Returns information about the company and the user associated to the token. responses: '200': description: OK /journals: get: operationId: getJournals tags: [Journals] summary: List journals description: 'List journals. Requires scope: journals:readonly or journals:all.' parameters: - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/Limit' responses: '200': { description: OK } '429': { $ref: '#/components/responses/TooManyRequests' } post: operationId: postJournals tags: [Journals] summary: Create a journal description: 'Create a journal. Requires scope: journals:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /journals/{id}: get: operationId: getJournal tags: [Journals] summary: Retrieve a journal parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } '404': { $ref: '#/components/responses/NotFound' } /ledger_accounts: get: operationId: getLedgerAccounts tags: [Ledger Accounts] summary: List ledger accounts description: 'Requires scope: ledger_accounts:readonly or ledger_accounts:all.' parameters: - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/Limit' responses: '200': { description: OK } post: operationId: postLedgerAccounts tags: [Ledger Accounts] summary: Create a ledger account description: 'Requires scope: ledger_accounts:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /ledger_accounts/{id}: get: operationId: getLedgerAccount tags: [Ledger Accounts] summary: Get a ledger account parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } put: operationId: updateLedgerAccount tags: [Ledger Accounts] summary: Update a ledger account description: 'Requires scope: ledger_accounts:all.' parameters: - $ref: '#/components/parameters/PathId' requestBody: required: true content: application/json: schema: { type: object } responses: '200': { description: OK } /ledger_entries: get: operationId: getLedgerEntries tags: [Ledger Entries] summary: List ledger entries description: 'Requires scope: ledger_entries:readonly or ledger_entries:all.' parameters: - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/Limit' responses: '200': { description: OK } post: operationId: postLedgerEntries tags: [Ledger Entries] summary: Create a ledger entry description: 'Requires scope: ledger_entries:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /ledger_entries/{id}: get: operationId: getLedgerEntry tags: [Ledger Entries] summary: Retrieve a ledger entry parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } put: operationId: putLedgerEntries tags: [Ledger Entries] summary: Update a ledger entry parameters: - $ref: '#/components/parameters/PathId' requestBody: required: true content: application/json: schema: { type: object } responses: '200': { description: OK } /trial_balance: get: operationId: getTrialBalance tags: [Ledger Entries] summary: Get the trial balance description: 'Returns the trial balance for the given period. Requires scope: trial_balance:readonly.' parameters: - name: period_start in: query schema: { type: string, format: date } - name: period_end in: query schema: { type: string, format: date } responses: '200': { description: OK } /fiscal_years: get: operationId: getFiscalYears tags: [Ledger Entries] summary: List company fiscal years description: 'Requires scope: fiscal_years:readonly.' responses: '200': { description: OK } /exports/general_ledger: post: operationId: exportGeneralLedger tags: [Accounting Exports] summary: Create a General Ledger export description: 'Creates an xlsx General Ledger export. Requires scope: exports:gl.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /exports/fec: post: operationId: exportFec tags: [Accounting Exports] summary: Create a FEC export description: 'Creates a FEC (Fichier des Ecritures Comptables) export. Requires scope: exports:fec.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /categories: get: operationId: getCategories tags: [Categories] summary: List categories description: 'Requires scope: categories:readonly or categories:all.' responses: '200': { description: OK } post: operationId: postCategories tags: [Categories] summary: Create a category description: 'Requires scope: categories:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /category_groups: get: operationId: getCategoryGroups tags: [Categories] summary: List category groups responses: '200': { description: OK } /customer_invoices: get: operationId: getCustomerInvoices tags: [Customer Invoices] summary: List customer invoices description: 'List customer invoices and credit notes. Requires scope: customer_invoices:readonly or customer_invoices:all.' parameters: - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Filter' responses: '200': { description: OK } '429': { $ref: '#/components/responses/TooManyRequests' } post: operationId: postCustomerInvoices tags: [Customer Invoices] summary: Create a customer invoice description: 'Create a draft or finalized customer invoice or credit note. Requires scope: customer_invoices:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } '422': { $ref: '#/components/responses/UnprocessableEntity' } /customer_invoices/import: post: operationId: importCustomerInvoices tags: [Customer Invoices] summary: Import an invoice with file attached description: 'Import a customer invoice with a file attached. Requires scope: customer_invoices:all.' requestBody: required: true content: multipart/form-data: schema: { type: object } responses: '201': { description: Created } /customer_invoices/{id}: get: operationId: getCustomerInvoice tags: [Customer Invoices] summary: Retrieve a customer invoice parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } put: operationId: updateCustomerInvoice tags: [Customer Invoices] summary: Update a customer invoice parameters: - $ref: '#/components/parameters/PathId' requestBody: required: true content: application/json: schema: { type: object } responses: '200': { description: OK } /customer_invoices/{id}/finalize: put: operationId: finalizeCustomerInvoice tags: [Customer Invoices] summary: Finalize a draft customer invoice description: 'Convert a draft invoice or credit note into a finalized one; once finalized it can no longer be edited.' parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } /customer_invoices/{id}/mark_as_paid: put: operationId: markAsPaidCustomerInvoice tags: [Customer Invoices] summary: Mark a customer invoice as paid parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } /customer_invoices/{id}/send_by_email: post: operationId: sendByEmailCustomerInvoice tags: [Customer Invoices] summary: Send a customer invoice by email description: 'Sends a finalized, imported customer invoice or credit note by email. May return 409 if the PDF is not yet generated; retry shortly.' parameters: - $ref: '#/components/parameters/PathId' responses: '204': { description: Email queued } '409': { $ref: '#/components/responses/Conflict' } /customer_invoices/{id}/matched_transactions: post: operationId: postCustomerInvoiceMatchedTransactions tags: [Customer Invoices] summary: Match a transaction to a customer invoice parameters: - $ref: '#/components/parameters/PathId' requestBody: required: true content: application/json: schema: { type: object } responses: '200': { description: OK } /supplier_invoices: get: operationId: getSupplierInvoices tags: [Supplier Invoices] summary: List supplier invoices description: 'Requires scope: supplier_invoices:readonly or supplier_invoices:all.' parameters: - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Filter' responses: '200': { description: OK } /supplier_invoices/import: post: operationId: importSupplierInvoice tags: [Supplier Invoices] summary: Import a supplier invoice with a file attached description: 'Requires scope: supplier_invoices:all.' requestBody: required: true content: multipart/form-data: schema: { type: object } responses: '201': { description: Created } /supplier_invoices/{id}: get: operationId: getSupplierInvoice tags: [Supplier Invoices] summary: Retrieve a supplier invoice parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } put: operationId: putSupplierInvoice tags: [Supplier Invoices] summary: Update a supplier invoice parameters: - $ref: '#/components/parameters/PathId' requestBody: required: true content: application/json: schema: { type: object } responses: '200': { description: OK } /supplier_invoices/{id}/validate_accounting: put: operationId: validateAccountingSupplierInvoice tags: [Supplier Invoices] summary: Validate the accounting of a supplier invoice description: Turn the supplier invoice into a Complete state. parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } /quotes: get: operationId: listQuotes tags: [Quotes] summary: List quotes description: 'Requires scope: quotes:readonly or quotes:all.' responses: '200': { description: OK } post: operationId: postQuotes tags: [Quotes] summary: Create a quote description: 'Requires scope: quotes:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /quotes/{id}: get: operationId: getQuote tags: [Quotes] summary: Retrieve a quote parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } /billing_subscriptions: get: operationId: getBillingSubscriptions tags: [Billing Subscriptions] summary: List billing subscriptions description: 'Requires scope: billing_subscriptions:readonly or billing_subscriptions:all.' responses: '200': { description: OK } post: operationId: postBillingSubscriptions tags: [Billing Subscriptions] summary: Create a billing subscription description: 'Pennylane generates the customer invoice each month. Requires scope: billing_subscriptions:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /products: get: operationId: getProducts tags: [Products] summary: List products description: 'Requires scope: products:readonly or products:all.' responses: '200': { description: OK } post: operationId: postProducts tags: [Products] summary: Create a product description: 'Requires scope: products:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /products/{id}: get: operationId: getProduct tags: [Products] summary: Retrieve a product parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } put: operationId: putProduct tags: [Products] summary: Update a product parameters: - $ref: '#/components/parameters/PathId' requestBody: required: true content: application/json: schema: { type: object } responses: '200': { description: OK } /customers: get: operationId: getCustomers tags: [Customers] summary: List customers (company and individual) description: 'Requires scope: customers:readonly or customers:all.' responses: '200': { description: OK } /customers/{id}: get: operationId: getCustomer tags: [Customers] summary: Retrieve a customer parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } /company_customers: post: operationId: postCompanyCustomer tags: [Customers] summary: Create a company customer description: 'Requires scope: customers:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /individual_customers: post: operationId: postIndividualCustomer tags: [Customers] summary: Create an individual customer description: 'Requires scope: customers:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /suppliers: get: operationId: getSuppliers tags: [Suppliers] summary: List suppliers description: 'Requires scope: suppliers:readonly or suppliers:all.' responses: '200': { description: OK } post: operationId: postSupplier tags: [Suppliers] summary: Create a supplier description: 'Requires scope: suppliers:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /suppliers/{id}: get: operationId: getSupplier tags: [Suppliers] summary: Retrieve a supplier parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } put: operationId: putSupplier tags: [Suppliers] summary: Update a supplier parameters: - $ref: '#/components/parameters/PathId' requestBody: required: true content: application/json: schema: { type: object } responses: '200': { description: OK } /bank_accounts: get: operationId: getBankAccounts tags: [Bank Accounts] summary: List bank accounts description: 'Requires scope: bank_accounts:readonly or bank_accounts:all.' responses: '200': { description: OK } post: operationId: postBankAccount tags: [Bank Accounts] summary: Create a bank account description: 'Requires scope: bank_accounts:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /bank_accounts/{id}: get: operationId: getBankAccount tags: [Bank Accounts] summary: Retrieve a bank account parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } /transactions: get: operationId: getTransactions tags: [Transactions] summary: List transactions description: 'Requires scope: transactions:readonly or transactions:all.' responses: '200': { description: OK } post: operationId: createTransaction tags: [Transactions] summary: Create a banking transaction description: 'Requires scope: transactions:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /transactions/{id}: get: operationId: getTransaction tags: [Transactions] summary: Retrieve a transaction parameters: - $ref: '#/components/parameters/PathId' responses: '200': { description: OK } put: operationId: updateTransaction tags: [Transactions] summary: Update a transaction parameters: - $ref: '#/components/parameters/PathId' requestBody: required: true content: application/json: schema: { type: object } responses: '200': { description: OK } /sepa_mandates: get: operationId: getSepaMandates tags: [Mandates] summary: List SEPA mandates description: 'Requires scope: customer_mandates:readonly or customer_mandates:all.' responses: '200': { description: OK } post: operationId: postSepaMandates tags: [Mandates] summary: Create a SEPA mandate description: 'Create a SEPA mandate to enable direct debit payments. Requires scope: customer_mandates:all.' requestBody: required: true content: application/json: schema: { type: object } responses: '201': { description: Created } /gocardless_mandates: get: operationId: getGocardlessMandates tags: [Mandates] summary: List GoCardless mandates description: 'Requires scope: customer_mandates:readonly or customer_mandates:all.' responses: '200': { description: OK } /file_attachments: post: operationId: postFileAttachments tags: [File Attachments] summary: Upload a file description: >- Upload a file to attach to any resource that provides a file_attachment_id. Maximum file size 100MB. Requires scope: file_attachments:all. requestBody: required: true content: multipart/form-data: schema: { type: object } responses: '201': { description: Created } /customer_invoices/changes: get: operationId: getCustomerInvoicesChanges tags: [Change Events] summary: Get customer invoice change events description: >- Returns the list of changes from the provided start_date (last 4 weeks retained), ordered by processed_at ASC. Requires scope: customer_invoices:readonly or customer_invoices:all. parameters: - name: start_date in: query schema: { type: string, format: date-time } responses: '200': { description: OK } /supplier_invoices/changes: get: operationId: getSupplierInvoicesChanges tags: [Change Events] summary: Get supplier invoice change events parameters: - name: start_date in: query schema: { type: string, format: date-time } responses: '200': { description: OK } /pa_registrations: get: operationId: getPaRegistrations tags: [E-Invoicing] summary: List PA (Plateforme Agréée) registrations description: >- Returns all PA registrations for the company, including activation status and exchange direction, for French e-invoicing onboarding. Requires scope: pa_registrations:readonly. responses: '200': { description: OK } components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: token description: >- Bearer token in the Authorization header. The token may be a Company API token, a Firm API token, or an OAuth 2.0 access token obtained via https://app.pennylane.com/oauth/authorize and /oauth/token. parameters: PathId: name: id in: path required: true description: Internal Pennylane resource id (v2 uses internal ids only, not source_id). schema: { type: integer } Cursor: name: cursor in: query required: false description: Opaque cursor for cursor-based pagination. schema: { type: string } Limit: name: limit in: query required: false description: Page size. schema: { type: integer, default: 100 } Filter: name: filter in: query required: false description: JSON filter expression applied on listing endpoints. schema: { type: string } responses: NotFound: description: Resource not found content: application/json: schema: { $ref: '#/components/schemas/Error' } Conflict: description: Conflict (e.g. PDF not yet generated) content: application/json: schema: { $ref: '#/components/schemas/Error' } UnprocessableEntity: description: Validation error content: application/json: schema: { $ref: '#/components/schemas/Error' } TooManyRequests: description: >- Rate limit exceeded (25 requests per 5 seconds per token). Includes retry-after, ratelimit-limit, ratelimit-remaining, and ratelimit-reset headers. headers: retry-after: schema: { type: integer } ratelimit-limit: schema: { type: integer } ratelimit-remaining: schema: { type: integer } ratelimit-reset: schema: { type: integer } content: application/json: schema: { $ref: '#/components/schemas/Error' } schemas: Error: type: object description: Consistent JSON error schema returned across the API. properties: status: type: integer message: type: string details: type: object description: Actionable field-level information, most useful for 422 validation errors.