---
title: "Create a customer invoice"
method: POST
path: "/api/external/v2/customer_invoices"
tags: ["Customer Invoices"]
---

# Create a customer invoice

`POST /api/external/v2/customer_invoices`

## Request

- Base URL: `https://app.pennylane.com`
- URL: `https://app.pennylane.com/api/external/v2/customer_invoices`
- Auth: OAuth 2
  - Authorization code: `https://app.pennylane.com/oauth/authorize`
  - Token URL: `https://app.pennylane.com/oauth/oauth/token` scopes: `customer_invoices:all`

This endpoint allows you to create a draft or finalized customer
invoice or credit note


> ℹ️
> This endpoint requires the following scope: `customer_invoices:all`

## Headers

- `X-Company-Id` string

## Request body

- union
  - object
    - `date` string, date, required: Invoice date (ISO 8601)
    - `deadline` string, date, required: Invoice payment deadline (ISO 8601)
    - `customer_id` integer, required: Customer identifier
    - `customer_invoice_template_id` integer: The customer invoice template ID
    - `sale_type` union: Type of sale printed on the invoice (Type de vente). `goods` is a supply of goods, `services` is a supply of services, and `goods_and_services` is both. `null` means the type has not been chosen. This is not invoice line `substance`. Omit this field to keep the invoice template default on create, or to leave the invoice unchanged on update. Send `null` to clear it. Finalized invoices cannot be updated with this field.
      - 'goods' | 'services' | 'goods_and_services': Type of sale printed on a customer invoice. This is not invoice line substance.
      - unknown
    - `pdf_invoice_free_text` string, nullable: For example, the contact details of the person to contact
    - `pdf_invoice_subject` string, nullable: Invoice title
    - `pdf_description` string, nullable: Invoice description. Maximum 5,000 characters.
    - `currency` 'EUR' | 'USD' | 'GBP' | 'AED' | 'AFN' | 'ALL' | 'AMD' | 'ANG' | 'AOA' | 'ARS' | 'AUD' | 'AWG' | 'AZN' | 'BAM' | 'BBD' | 'BDT' | 'BGN' | 'BHD' | 'BIF' | 'BMD' | 'BND' | 'BOB' | 'BRL' | 'BSD' | 'BTN' | 'BWP' | 'BYN' | 'BYR' | 'BZD' | 'CAD' | 'CDF' | 'CHE' | 'CHF' | 'CLF' | 'CLP' | 'CNY' | 'COP' | 'CRC' | 'CUC' | 'CUP' | 'CVE' | 'CZK' | 'DJF' | 'DKK' | 'DOP' | 'DZD' | 'EGP' | 'ERN' | 'ETB' | 'FJD' | 'FKP' | 'GEL' | 'GGP' | 'GHS' | 'GIP' | 'GMD' | 'GNF' | 'GTQ' | 'GYD' | 'HKD' | 'HNL' | 'HRK' | 'HTG' | 'HUF' | 'IDR' | 'ILS' | 'IMP' | 'INR' | 'IQD' | 'IRR' | 'ISK' | 'JEP' | 'JMD' | 'JOD' | 'JPY' | 'KES' | 'KGS' | 'KHR' | 'KMF' | 'KPW' | 'KRW' | 'KWD' | 'KYD' | 'KZT' | 'LAK' | 'LBP' | 'LKR' | 'LRD' | 'LSL' | 'LTL' | 'LVL' | 'LYD' | 'MAD' | 'MDL' | 'MGA' | 'MKD' | 'MMK' | 'MNT' | 'MOP' | 'MRO' | 'MRU' | 'MUR' | 'MVR' | 'MWK' | 'MXN' | 'MYR' | 'MZN' | 'NAD' | 'NGN' | 'NIO' | 'NOK' | 'NPR' | 'NZD' | 'OMR' | 'PAB' | 'PEN' | 'PGK' | 'PHP' | 'PKR' | 'PLN' | 'PYG' | 'QAR' | 'RON' | 'RSD' | 'RUB' | 'RWF' | 'SAR' | 'SBD' | 'SCR' | 'SDG' | 'SEK' | 'SGD' | 'SHP' | 'SLL' | 'SLE' | 'SOS' | 'SRD' | 'STD' | 'SVC' | 'SYP' | 'SZL' | 'THB' | 'TJS' | 'TMT' | 'TND' | 'TOP' | 'TRY' | 'TTD' | 'TWD' | 'TZS' | 'UAH' | 'UGX' | 'UYU' | 'UZS' | 'VEF' | 'VES' | 'VND' | 'VUV' | 'WST' | 'XAF' | 'XCD' | 'XDR' | 'XOF' | 'XPF' | 'YER' | 'ZAR' | 'ZMK' | 'ZMW' | 'ZWL'
    - `special_mention` string, nullable: Additional details. maximum 20,000 characters.
    - `language` 'fr_FR' | 'en_GB' | 'de_DE' | 'es_ES': The local default is based on the thirdparty (customer / supplier ) billing_language . In case the customer is not present, we will default to the company locale.
    - `discount` object
      - `type` 'absolute' | 'relative', required: Discount type. - absolute if it is an amount - relative if it is a percentage
      - `value` string, required: Discount value on the total amount before tax of the invoice
    - `invoice_line_sections` object[]
      - `title` string: Title of the invoice line section
      - `description` string: Description of the invoice line section
      - `rank` integer, required: Defines the order in which sections will be displayed on the invoice. Each section has to have a different rank, starting from 1 and incrementing next values by 1
    - `label` string, nullable: Custom label for the invoice used on accounting (ledger) entries. If not provided, Pennylane generates a label automatically.
    - `external_reference` string: A unique external reference you can provide to track this customer invoice. If not provided, Pennylane will generate an identifier for you.
    - `purchase_order_reference` string, nullable: Buyer's purchase order reference (e-invoice field BT-13). Maximum 50 characters.
    - `contract_reference` string, nullable: Contract reference (e-invoice field BT-12). Maximum 50 characters.
    - `draft` true, required: Indicates if the invoice is in draft status (has not been finalized)
    - `invoice_lines` union[], required
      - union
        - object: Provide only the product_id to automatically populate label, raw_currency_unit_price, unit, vat_rate, and ledger_account_id. You can override any of these fields by providing them explicitly.
          - `product_id` integer, required: The product ID. Auto-fills label, raw_currency_unit_price, unit, vat_rate, and ledger_account_id from the product.
          - `label` string: Line item label
          - `ledger_account_id` integer: The ledger account ID
          - `substance` 'goods' | 'services': Resolves the line's ledger account to the company's goods or services account. When provided together with `product_id`, `product_id` auto-fill runs first. If the resulting ledger account does not match `substance`, the request returns 422. When provided together with `ledger_account_id`, both must refer to the same account. If they do not match, the request returns 422.
          - `raw_currency_unit_price` string: The unit price excluding taxes (undiscounted if a discount is set). Can be set up to 6 decimals.
          - `unit` string: Line item unit (type of unit)
          - `vat_rate` 'FR_1_05' | 'FR_1_75' | 'FR_09' | 'FR_21' | 'FR_40' | 'FR_50' | 'FR_55' | 'FR_60' | 'FR_65' | 'FR_85' | 'FR_92' | 'FR_100' | 'FR_130' | 'FR_15_385' | 'FR_160' | 'FR_196' | 'FR_200' | 'AD_10' | 'AD_45' | 'AD_95' | 'AT_100' | 'AT_130' | 'AT_190' | 'AT_200' | 'BE_60' | 'BE_120' | 'BE_210' | 'BG_90' | 'BG_200' | 'CH_25' | 'CH_37' | 'CH_77' | 'CH_26' | 'CH_38' | 'CH_81' | 'CY_30' | 'CY_50' | 'CY_80' | 'CY_90' | 'CY_190' | 'CZ_100' | 'CZ_120' | 'CZ_150' | 'CZ_210' | 'DE_70' | 'DE_190' | 'DK_250' | 'EE_90' | 'EE_200' | 'EE_220' | 'EE_240' | 'ES_40' | 'ES_70' | 'ES_100' | 'ES_210' | 'FI_100' | 'FI_135' | 'FI_140' | 'FI_240' | 'FI_255' | 'GB_50' | 'GB_200' | 'GR_60' | 'GR_130' | 'GR_170' | 'GR_240' | 'GR_40' | 'HR_50' | 'HR_130' | 'HR_250' | 'HU_50' | 'HU_180' | 'HU_270' | 'IE_48' | 'IE_90' | 'IE_135' | 'IE_210' | 'IE_230' | 'IT_40' | 'IT_50' | 'IT_100' | 'IT_220' | 'LT_50' | 'LT_90' | 'LT_120' | 'LT_210' | 'LU_30' | 'LU_70' | 'LU_80' | 'LU_120' | 'LU_130' | 'LU_140' | 'LU_160' | 'LU_170' | 'LV_50' | 'LV_120' | 'LV_210' | 'MC_09' | 'MC_21' | 'MC_55' | 'MC_85' | 'MC_100' | 'MC_200' | 'MT_50' | 'MT_70' | 'MT_120' | 'MT_180' | 'MU_150' | 'NL_90' | 'NL_210' | 'PL_50' | 'PL_80' | 'PL_230' | 'PT_60' | 'PT_130' | 'PT_160' | 'PT_180' | 'PT_220' | 'PT_230' | 'RO_50' | 'RO_90' | 'RO_110' | 'RO_190' | 'RO_210' | 'SE_60' | 'SE_120' | 'SE_250' | 'SI_50' | 'SI_95' | 'SI_220' | 'SK_50' | 'SK_100' | 'SK_190' | 'SK_200' | 'SK_230' | 'NO_120' | 'NO_150' | 'NO_250' | 'DE_70_BU0002' | 'DE_190_BU0003' | 'DE_70_BU0008' | 'DE_190_BU0009' | 'DE_intracom_70_BU0012' | 'DE_intracom_190_BU0013' | 'DE_190_electronic_BU0226' | 'exempt' | 'DE_intracom_exempt_BU0011' | 'DE_intracom_exempt_BU0047' | 'DE_intracom_exempt_BU0233' | 'DE_exempt_BU0001' | 'DE_exempt_BU0181' | 'DE_exempt_BU0490' | 'intracom_21' | 'intracom_55' | 'intracom_85' | 'intracom_100' | 'crossborder' | 'ES_intracom_sales_goods' | 'ES_intracom_sales_services' | 'DE_intracom_70_BU0018' | 'DE_intracom_190_BU0019' | 'DE_intracom_190_BU0506' | 'extracom' | 'DE_extracom_BU0173' | 'DE_extracom_BU0191' | 'DE_extracom_190_BU0511' | 'ES_isp_sales' | 'ES_suplido' | 'FR_85_construction' | 'FR_100_construction' | 'FR_200_construction' | 'DE_exempt_construction_BU0046' | 'DE_70_construction_BU0091' | 'DE_190_construction_BU0094' | 'DE_190_construction_BU0526' | 'DE_190_construction_BU0546' | 'ES_isp_purchases_210' | 'ES_isp_purchases_100' | 'mixed': Product VAT rate. A 20% VAT in France is FR_200.
          - `quantity` number, required: Line item quantity (number of items)
          - `section_rank` integer: Has to correspond to the rank number of a line items section in which the line item should be
          - `discount` object
            - `type` 'absolute' | 'relative', required: Discount type. - absolute if it is an amount - relative if it is a percentage
            - `value` string, required: Discount value on the total amount before tax of the line
          - `description` string, nullable: The description of the invoice line
          - `custom_fields` object[]: **Experimental** — under active development, may change without notice. Do not rely on this field in production integrations.
            - `name` string, required
            - `value` union, required: Format depends on the field type: plain string for `text`; numeric string for `number` (e.g. `"42.5"`); ISO 8601 date for `date` (e.g. `"2025-01-15"`); option label for `single_select`; array of option labels for `multi_select`.
              - …
          - `performance_period` union
            - object: Date range during which the service or delivery was performed (ISO 8601). Used for German VAT accounting (Leistungsdatum). Only accepted for companies using German accounting, otherwise the request is rejected. Omit it to keep the current performance period, or set it to null to remove it.
              - …
            - unknown
        - object: Create an invoice line by providing all required fields explicitly without referencing a product.
          - `label` string, required: Line item label
          - `ledger_account_id` integer: The ledger account ID
          - `substance` 'goods' | 'services': Resolves the line's ledger account to the company's goods or services account. When provided together with `ledger_account_id`, both must refer to the same account. If they do not match, the request returns 422.
          - `raw_currency_unit_price` string, required: The unit price excluding taxes (undiscounted if a discount is set). Can be set up to 6 decimals.
          - `unit` string, required: Line item unit (type of unit)
          - `vat_rate` 'FR_1_05' | 'FR_1_75' | 'FR_09' | 'FR_21' | 'FR_40' | 'FR_50' | 'FR_55' | 'FR_60' | 'FR_65' | 'FR_85' | 'FR_92' | 'FR_100' | 'FR_130' | 'FR_15_385' | 'FR_160' | 'FR_196' | 'FR_200' | 'AD_10' | 'AD_45' | 'AD_95' | 'AT_100' | 'AT_130' | 'AT_190' | 'AT_200' | 'BE_60' | 'BE_120' | 'BE_210' | 'BG_90' | 'BG_200' | 'CH_25' | 'CH_37' | 'CH_77' | 'CH_26' | 'CH_38' | 'CH_81' | 'CY_30' | 'CY_50' | 'CY_80' | 'CY_90' | 'CY_190' | 'CZ_100' | 'CZ_120' | 'CZ_150' | 'CZ_210' | 'DE_70' | 'DE_190' | 'DK_250' | 'EE_90' | 'EE_200' | 'EE_220' | 'EE_240' | 'ES_40' | 'ES_70' | 'ES_100' | 'ES_210' | 'FI_100' | 'FI_135' | 'FI_140' | 'FI_240' | 'FI_255' | 'GB_50' | 'GB_200' | 'GR_60' | 'GR_130' | 'GR_170' | 'GR_240' | 'GR_40' | 'HR_50' | 'HR_130' | 'HR_250' | 'HU_50' | 'HU_180' | 'HU_270' | 'IE_48' | 'IE_90' | 'IE_135' | 'IE_210' | 'IE_230' | 'IT_40' | 'IT_50' | 'IT_100' | 'IT_220' | 'LT_50' | 'LT_90' | 'LT_120' | 'LT_210' | 'LU_30' | 'LU_70' | 'LU_80' | 'LU_120' | 'LU_130' | 'LU_140' | 'LU_160' | 'LU_170' | 'LV_50' | 'LV_120' | 'LV_210' | 'MC_09' | 'MC_21' | 'MC_55' | 'MC_85' | 'MC_100' | 'MC_200' | 'MT_50' | 'MT_70' | 'MT_120' | 'MT_180' | 'MU_150' | 'NL_90' | 'NL_210' | 'PL_50' | 'PL_80' | 'PL_230' | 'PT_60' | 'PT_130' | 'PT_160' | 'PT_180' | 'PT_220' | 'PT_230' | 'RO_50' | 'RO_90' | 'RO_110' | 'RO_190' | 'RO_210' | 'SE_60' | 'SE_120' | 'SE_250' | 'SI_50' | 'SI_95' | 'SI_220' | 'SK_50' | 'SK_100' | 'SK_190' | 'SK_200' | 'SK_230' | 'NO_120' | 'NO_150' | 'NO_250' | 'DE_70_BU0002' | 'DE_190_BU0003' | 'DE_70_BU0008' | 'DE_190_BU0009' | 'DE_intracom_70_BU0012' | 'DE_intracom_190_BU0013' | 'DE_190_electronic_BU0226' | 'exempt' | 'DE_intracom_exempt_BU0011' | 'DE_intracom_exempt_BU0047' | 'DE_intracom_exempt_BU0233' | 'DE_exempt_BU0001' | 'DE_exempt_BU0181' | 'DE_exempt_BU0490' | 'intracom_21' | 'intracom_55' | 'intracom_85' | 'intracom_100' | 'crossborder' | 'ES_intracom_sales_goods' | 'ES_intracom_sales_services' | 'DE_intracom_70_BU0018' | 'DE_intracom_190_BU0019' | 'DE_intracom_190_BU0506' | 'extracom' | 'DE_extracom_BU0173' | 'DE_extracom_BU0191' | 'DE_extracom_190_BU0511' | 'ES_isp_sales' | 'ES_suplido' | 'FR_85_construction' | 'FR_100_construction' | 'FR_200_construction' | 'DE_exempt_construction_BU0046' | 'DE_70_construction_BU0091' | 'DE_190_construction_BU0094' | 'DE_190_construction_BU0526' | 'DE_190_construction_BU0546' | 'ES_isp_purchases_210' | 'ES_isp_purchases_100' | 'mixed', required: Product VAT rate. A 20% VAT in France is FR_200.
          - `quantity` number, required: Line item quantity (number of items)
          - `section_rank` integer: Has to correspond to the rank number of a line items section in which the line item should be
          - `discount` object
            - `type` 'absolute' | 'relative', required: Discount type. - absolute if it is an amount - relative if it is a percentage
            - `value` string, required: Discount value on the total amount before tax of the line
          - `description` string, nullable: The description of the invoice line
          - `custom_fields` object[]: **Experimental** — under active development, may change without notice. Do not rely on this field in production integrations.
            - `name` string, required
            - `value` union, required: Format depends on the field type: plain string for `text`; numeric string for `number` (e.g. `"42.5"`); ISO 8601 date for `date` (e.g. `"2025-01-15"`); option label for `single_select`; array of option labels for `multi_select`.
              - …
          - `performance_period` union
            - object: Date range during which the service or delivery was performed (ISO 8601). Used for German VAT accounting (Leistungsdatum). Only accepted for companies using German accounting, otherwise the request is rejected. Omit it to keep the current performance period, or set it to null to remove it.
              - …
            - unknown
    - `installments` object[]: Optional list of installments for this invoice. If not provided, a single installment matching the invoice total is created automatically. The sum of all installments' `amount` values must equal the invoice total amount with tax. Invoices issued by a billing subscription cannot have multiple installments. > ℹ️ > This param requires a company plan that has access to Installments, otherwise responds with 403. > ⚠️ **Warning**: This feature is in alpha > The installments param will be ignored until further rollout and the request will proceed as if it was made without it > If you plan to rely on it, please get in touch with us first
      - `deadline` string, date, required: Installment payment deadline (ISO 8601)
      - `amount` string, required: Installment amount (in invoice currency)
      - `payment_methods` string[]
  - object
    - `date` string, date, required: Invoice date (ISO 8601)
    - `deadline` string, date, required: Invoice payment deadline (ISO 8601)
    - `customer_id` integer, required: Customer identifier
    - `customer_invoice_template_id` integer: The customer invoice template ID
    - `sale_type` union: Type of sale printed on the invoice (Type de vente). `goods` is a supply of goods, `services` is a supply of services, and `goods_and_services` is both. `null` means the type has not been chosen. This is not invoice line `substance`. Omit this field to keep the invoice template default on create, or to leave the invoice unchanged on update. Send `null` to clear it. Finalized invoices cannot be updated with this field.
      - 'goods' | 'services' | 'goods_and_services': Type of sale printed on a customer invoice. This is not invoice line substance.
      - unknown
    - `pdf_invoice_free_text` string, nullable: For example, the contact details of the person to contact
    - `pdf_invoice_subject` string, nullable: Invoice title
    - `pdf_description` string, nullable: Invoice description. Maximum 5,000 characters.
    - `currency` 'EUR' | 'USD' | 'GBP' | 'AED' | 'AFN' | 'ALL' | 'AMD' | 'ANG' | 'AOA' | 'ARS' | 'AUD' | 'AWG' | 'AZN' | 'BAM' | 'BBD' | 'BDT' | 'BGN' | 'BHD' | 'BIF' | 'BMD' | 'BND' | 'BOB' | 'BRL' | 'BSD' | 'BTN' | 'BWP' | 'BYN' | 'BYR' | 'BZD' | 'CAD' | 'CDF' | 'CHE' | 'CHF' | 'CLF' | 'CLP' | 'CNY' | 'COP' | 'CRC' | 'CUC' | 'CUP' | 'CVE' | 'CZK' | 'DJF' | 'DKK' | 'DOP' | 'DZD' | 'EGP' | 'ERN' | 'ETB' | 'FJD' | 'FKP' | 'GEL' | 'GGP' | 'GHS' | 'GIP' | 'GMD' | 'GNF' | 'GTQ' | 'GYD' | 'HKD' | 'HNL' | 'HRK' | 'HTG' | 'HUF' | 'IDR' | 'ILS' | 'IMP' | 'INR' | 'IQD' | 'IRR' | 'ISK' | 'JEP' | 'JMD' | 'JOD' | 'JPY' | 'KES' | 'KGS' | 'KHR' | 'KMF' | 'KPW' | 'KRW' | 'KWD' | 'KYD' | 'KZT' | 'LAK' | 'LBP' | 'LKR' | 'LRD' | 'LSL' | 'LTL' | 'LVL' | 'LYD' | 'MAD' | 'MDL' | 'MGA' | 'MKD' | 'MMK' | 'MNT' | 'MOP' | 'MRO' | 'MRU' | 'MUR' | 'MVR' | 'MWK' | 'MXN' | 'MYR' | 'MZN' | 'NAD' | 'NGN' | 'NIO' | 'NOK' | 'NPR' | 'NZD' | 'OMR' | 'PAB' | 'PEN' | 'PGK' | 'PHP' | 'PKR' | 'PLN' | 'PYG' | 'QAR' | 'RON' | 'RSD' | 'RUB' | 'RWF' | 'SAR' | 'SBD' | 'SCR' | 'SDG' | 'SEK' | 'SGD' | 'SHP' | 'SLL' | 'SLE' | 'SOS' | 'SRD' | 'STD' | 'SVC' | 'SYP' | 'SZL' | 'THB' | 'TJS' | 'TMT' | 'TND' | 'TOP' | 'TRY' | 'TTD' | 'TWD' | 'TZS' | 'UAH' | 'UGX' | 'UYU' | 'UZS' | 'VEF' | 'VES' | 'VND' | 'VUV' | 'WST' | 'XAF' | 'XCD' | 'XDR' | 'XOF' | 'XPF' | 'YER' | 'ZAR' | 'ZMK' | 'ZMW' | 'ZWL'
    - `special_mention` string, nullable: Additional details. maximum 20,000 characters.
    - `language` 'fr_FR' | 'en_GB' | 'de_DE' | 'es_ES': The local default is based on the thirdparty (customer / supplier ) billing_language . In case the customer is not present, we will default to the company locale.
    - `label` string, nullable: Custom label for the invoice used on accounting (ledger) entries. If not provided, Pennylane generates a label automatically.
    - `discount` object
      - `type` 'absolute' | 'relative', required: Discount type. - absolute if it is an amount - relative if it is a percentage
      - `value` string, required: Discount value on the total amount before tax of the invoice
    - `invoice_line_sections` object[]
      - `title` string: Title of the invoice line section
      - `description` string: Description of the invoice line section
      - `rank` integer, required: Defines the order in which sections will be displayed on the invoice. Each section has to have a different rank, starting from 1 and incrementing next values by 1
    - `external_reference` string: A unique external reference you can provide to track this customer invoice. If not provided, Pennylane will generate an identifier for you.
    - `purchase_order_reference` string, nullable: Buyer's purchase order reference (e-invoice field BT-13). Maximum 50 characters.
    - `contract_reference` string, nullable: Contract reference (e-invoice field BT-12). Maximum 50 characters.
    - `draft` false: Indicates if the invoice is in draft status (has not been finalized)
    - `transaction_reference` object: By adding this field you can automatically reconcile the newly created invoice with a transaction. See documentation about [automatic payment matching](https://pennylane.readme.io/v2.0/docs/automating-payment-matching).
      - `banking_provider` 'stripe' | 'gocardless' | 'bank' | 'budgetinsight' | 'helloasso', required: The banking provider for the transaction
      - `provider_field_name` 'payment_id' | 'charge_id' | 'report_id' | 'webid' | 'label' | 'order_id', required: Name of the field that you want to match
      - `provider_field_value` string, required: Value that you want to match. With `banking_provider: stripe` or `gocardless`, the value is matched exactly against the reference with the same `provider_field_name` synced from that provider, on non-archived transactions. With `banking_provider: bank` and `provider_field_name: label`, every non-archived bank transaction whose label contains this value as a whole word is matched, including transactions already matched to other documents. The match is case-sensitive, and a value that does not start and end with a letter, digit or underscore never matches. Use a value that identifies a single payment, such as a card transaction ID: a merchant name or a short generic value groups unrelated documents together. Pass the literal string `invoice_number` to match on this invoice's number instead of a fixed value. Other combinations do not match any transaction. In all cases, matching runs again on every update of this invoice.
    - `invoice_lines` union[], required
      - union
        - object: Provide only the product_id to automatically populate label, raw_currency_unit_price, unit, vat_rate, and ledger_account_id. You can override any of these fields by providing them explicitly.
          - `product_id` integer, required: The product ID. Auto-fills label, raw_currency_unit_price, unit, vat_rate, and ledger_account_id from the product.
          - `label` string: Line item label
          - `ledger_account_id` integer: The ledger account ID
          - `substance` 'goods' | 'services': Resolves the line's ledger account to the company's goods or services account. When provided together with `product_id`, `product_id` auto-fill runs first. If the resulting ledger account does not match `substance`, the request returns 422. When provided together with `ledger_account_id`, both must refer to the same account. If they do not match, the request returns 422.
          - `raw_currency_unit_price` string: The unit price excluding taxes
          - `unit` string: Line item unit (type of unit)
          - `vat_rate` 'FR_1_05' | 'FR_1_75' | 'FR_09' | 'FR_21' | 'FR_40' | 'FR_50' | 'FR_55' | 'FR_60' | 'FR_65' | 'FR_85' | 'FR_92' | 'FR_100' | 'FR_130' | 'FR_15_385' | 'FR_160' | 'FR_196' | 'FR_200' | 'AD_10' | 'AD_45' | 'AD_95' | 'AT_100' | 'AT_130' | 'AT_190' | 'AT_200' | 'BE_60' | 'BE_120' | 'BE_210' | 'BG_90' | 'BG_200' | 'CH_25' | 'CH_37' | 'CH_77' | 'CH_26' | 'CH_38' | 'CH_81' | 'CY_30' | 'CY_50' | 'CY_80' | 'CY_90' | 'CY_190' | 'CZ_100' | 'CZ_120' | 'CZ_150' | 'CZ_210' | 'DE_70' | 'DE_190' | 'DK_250' | 'EE_90' | 'EE_200' | 'EE_220' | 'EE_240' | 'ES_40' | 'ES_70' | 'ES_100' | 'ES_210' | 'FI_100' | 'FI_135' | 'FI_140' | 'FI_240' | 'FI_255' | 'GB_50' | 'GB_200' | 'GR_60' | 'GR_130' | 'GR_170' | 'GR_240' | 'GR_40' | 'HR_50' | 'HR_130' | 'HR_250' | 'HU_50' | 'HU_180' | 'HU_270' | 'IE_48' | 'IE_90' | 'IE_135' | 'IE_210' | 'IE_230' | 'IT_40' | 'IT_50' | 'IT_100' | 'IT_220' | 'LT_50' | 'LT_90' | 'LT_120' | 'LT_210' | 'LU_30' | 'LU_70' | 'LU_80' | 'LU_120' | 'LU_130' | 'LU_140' | 'LU_160' | 'LU_170' | 'LV_50' | 'LV_120' | 'LV_210' | 'MC_09' | 'MC_21' | 'MC_55' | 'MC_85' | 'MC_100' | 'MC_200' | 'MT_50' | 'MT_70' | 'MT_120' | 'MT_180' | 'MU_150' | 'NL_90' | 'NL_210' | 'PL_50' | 'PL_80' | 'PL_230' | 'PT_60' | 'PT_130' | 'PT_160' | 'PT_180' | 'PT_220' | 'PT_230' | 'RO_50' | 'RO_90' | 'RO_110' | 'RO_190' | 'RO_210' | 'SE_60' | 'SE_120' | 'SE_250' | 'SI_50' | 'SI_95' | 'SI_220' | 'SK_50' | 'SK_100' | 'SK_190' | 'SK_200' | 'SK_230' | 'NO_120' | 'NO_150' | 'NO_250' | 'DE_70_BU0002' | 'DE_190_BU0003' | 'DE_70_BU0008' | 'DE_190_BU0009' | 'DE_intracom_70_BU0012' | 'DE_intracom_190_BU0013' | 'DE_190_electronic_BU0226' | 'exempt' | 'DE_intracom_exempt_BU0011' | 'DE_intracom_exempt_BU0047' | 'DE_intracom_exempt_BU0233' | 'DE_exempt_BU0001' | 'DE_exempt_BU0181' | 'DE_exempt_BU0490' | 'intracom_21' | 'intracom_55' | 'intracom_85' | 'intracom_100' | 'crossborder' | 'ES_intracom_sales_goods' | 'ES_intracom_sales_services' | 'DE_intracom_70_BU0018' | 'DE_intracom_190_BU0019' | 'DE_intracom_190_BU0506' | 'extracom' | 'DE_extracom_BU0173' | 'DE_extracom_BU0191' | 'DE_extracom_190_BU0511' | 'ES_isp_sales' | 'ES_suplido' | 'FR_85_construction' | 'FR_100_construction' | 'FR_200_construction' | 'DE_exempt_construction_BU0046' | 'DE_70_construction_BU0091' | 'DE_190_construction_BU0094' | 'DE_190_construction_BU0526' | 'DE_190_construction_BU0546' | 'ES_isp_purchases_210' | 'ES_isp_purchases_100' | 'mixed': Product VAT rate. A 20% VAT in France is FR_200.
          - `quantity` number, required: Line item quantity (number of items)
          - `section_rank` integer: Has to correspond to the rank number of a line items section in which the line item should be
          - `discount` object
            - `type` 'absolute' | 'relative', required: Discount type. - absolute if it is an amount - relative if it is a percentage
            - `value` string, required: Discount value on the total amount before tax of the line
          - `description` string, nullable: The description of the invoice line
          - `imputation_dates` object, nullable
            - `start_date` string, date, required: Start date of the imputation period (ISO 8601)
            - `end_date` string, date, required: End date of the imputation period (ISO 8601)
          - `performance_period` union
            - object: Date range during which the service or delivery was performed (ISO 8601). Used for German VAT accounting (Leistungsdatum). Only accepted for companies using German accounting, otherwise the request is rejected. Omit it to keep the current performance period, or set it to null to remove it.
              - …
            - unknown
        - object: Create an invoice line by providing all required fields explicitly without referencing a product.
          - `label` string, required: Line item label
          - `ledger_account_id` integer: The ledger account ID
          - `substance` 'goods' | 'services': Resolves the line's ledger account to the company's goods or services account. When provided together with `ledger_account_id`, both must refer to the same account. If they do not match, the request returns 422.
          - `raw_currency_unit_price` string, required: The unit price excluding taxes (undiscounted if a discount is set). Can be set up to 6 decimals.
          - `unit` string, required: Line item unit (type of unit)
          - `vat_rate` 'FR_1_05' | 'FR_1_75' | 'FR_09' | 'FR_21' | 'FR_40' | 'FR_50' | 'FR_55' | 'FR_60' | 'FR_65' | 'FR_85' | 'FR_92' | 'FR_100' | 'FR_130' | 'FR_15_385' | 'FR_160' | 'FR_196' | 'FR_200' | 'AD_10' | 'AD_45' | 'AD_95' | 'AT_100' | 'AT_130' | 'AT_190' | 'AT_200' | 'BE_60' | 'BE_120' | 'BE_210' | 'BG_90' | 'BG_200' | 'CH_25' | 'CH_37' | 'CH_77' | 'CH_26' | 'CH_38' | 'CH_81' | 'CY_30' | 'CY_50' | 'CY_80' | 'CY_90' | 'CY_190' | 'CZ_100' | 'CZ_120' | 'CZ_150' | 'CZ_210' | 'DE_70' | 'DE_190' | 'DK_250' | 'EE_90' | 'EE_200' | 'EE_220' | 'EE_240' | 'ES_40' | 'ES_70' | 'ES_100' | 'ES_210' | 'FI_100' | 'FI_135' | 'FI_140' | 'FI_240' | 'FI_255' | 'GB_50' | 'GB_200' | 'GR_60' | 'GR_130' | 'GR_170' | 'GR_240' | 'GR_40' | 'HR_50' | 'HR_130' | 'HR_250' | 'HU_50' | 'HU_180' | 'HU_270' | 'IE_48' | 'IE_90' | 'IE_135' | 'IE_210' | 'IE_230' | 'IT_40' | 'IT_50' | 'IT_100' | 'IT_220' | 'LT_50' | 'LT_90' | 'LT_120' | 'LT_210' | 'LU_30' | 'LU_70' | 'LU_80' | 'LU_120' | 'LU_130' | 'LU_140' | 'LU_160' | 'LU_170' | 'LV_50' | 'LV_120' | 'LV_210' | 'MC_09' | 'MC_21' | 'MC_55' | 'MC_85' | 'MC_100' | 'MC_200' | 'MT_50' | 'MT_70' | 'MT_120' | 'MT_180' | 'MU_150' | 'NL_90' | 'NL_210' | 'PL_50' | 'PL_80' | 'PL_230' | 'PT_60' | 'PT_130' | 'PT_160' | 'PT_180' | 'PT_220' | 'PT_230' | 'RO_50' | 'RO_90' | 'RO_110' | 'RO_190' | 'RO_210' | 'SE_60' | 'SE_120' | 'SE_250' | 'SI_50' | 'SI_95' | 'SI_220' | 'SK_50' | 'SK_100' | 'SK_190' | 'SK_200' | 'SK_230' | 'NO_120' | 'NO_150' | 'NO_250' | 'DE_70_BU0002' | 'DE_190_BU0003' | 'DE_70_BU0008' | 'DE_190_BU0009' | 'DE_intracom_70_BU0012' | 'DE_intracom_190_BU0013' | 'DE_190_electronic_BU0226' | 'exempt' | 'DE_intracom_exempt_BU0011' | 'DE_intracom_exempt_BU0047' | 'DE_intracom_exempt_BU0233' | 'DE_exempt_BU0001' | 'DE_exempt_BU0181' | 'DE_exempt_BU0490' | 'intracom_21' | 'intracom_55' | 'intracom_85' | 'intracom_100' | 'crossborder' | 'ES_intracom_sales_goods' | 'ES_intracom_sales_services' | 'DE_intracom_70_BU0018' | 'DE_intracom_190_BU0019' | 'DE_intracom_190_BU0506' | 'extracom' | 'DE_extracom_BU0173' | 'DE_extracom_BU0191' | 'DE_extracom_190_BU0511' | 'ES_isp_sales' | 'ES_suplido' | 'FR_85_construction' | 'FR_100_construction' | 'FR_200_construction' | 'DE_exempt_construction_BU0046' | 'DE_70_construction_BU0091' | 'DE_190_construction_BU0094' | 'DE_190_construction_BU0526' | 'DE_190_construction_BU0546' | 'ES_isp_purchases_210' | 'ES_isp_purchases_100' | 'mixed', required: Product VAT rate. A 20% VAT in France is FR_200.
          - `quantity` number, required: Line item quantity (number of items)
          - `section_rank` integer: Has to correspond to the rank number of a line items section in which the line item should be
          - `discount` object
            - `type` 'absolute' | 'relative', required: Discount type. - absolute if it is an amount - relative if it is a percentage
            - `value` string, required: Discount value on the total amount before tax of the line
          - `description` string, nullable: The description of the invoice line
          - `imputation_dates` object, nullable
            - `start_date` string, date, required: Start date of the imputation period (ISO 8601)
            - `end_date` string, date, required: End date of the imputation period (ISO 8601)
          - `performance_period` union
            - object: Date range during which the service or delivery was performed (ISO 8601). Used for German VAT accounting (Leistungsdatum). Only accepted for companies using German accounting, otherwise the request is rejected. Omit it to keep the current performance period, or set it to null to remove it.
              - …
            - unknown
    - `installments` object[]: Optional list of installments for this invoice. If not provided, a single installment matching the invoice total is created automatically. The sum of all installments' `amount` values must equal the invoice total amount with tax. Invoices issued by a billing subscription cannot have multiple installments. > ℹ️ > This param requires a company plan that has access to Installments, otherwise responds with 403. > ⚠️ **Warning**: This feature is in alpha > The installments param will be ignored until further rollout and the request will proceed as if it was made without it > If you plan to rely on it, please get in touch with us first
      - `deadline` string, date, required: Installment payment deadline (ISO 8601)
      - `amount` string, required: Installment amount (in invoice currency)
      - `payment_methods` string[]

## Response `201`

Renders the created finalized invoice

- object
  - `id` integer, required: Invoice identifier
  - `label` string, nullable, required
  - `invoice_number` string, required
  - `currency` 'EUR' | 'USD' | 'GBP' | 'AED' | 'AFN' | 'ALL' | 'AMD' | 'ANG' | 'AOA' | 'ARS' | 'AUD' | 'AWG' | 'AZN' | 'BAM' | 'BBD' | 'BDT' | 'BGN' | 'BHD' | 'BIF' | 'BMD' | 'BND' | 'BOB' | 'BRL' | 'BSD' | 'BTN' | 'BWP' | 'BYN' | 'BYR' | 'BZD' | 'CAD' | 'CDF' | 'CHE' | 'CHF' | 'CLF' | 'CLP' | 'CNY' | 'COP' | 'CRC' | 'CUC' | 'CUP' | 'CVE' | 'CZK' | 'DJF' | 'DKK' | 'DOP' | 'DZD' | 'EGP' | 'ERN' | 'ETB' | 'FJD' | 'FKP' | 'GEL' | 'GGP' | 'GHS' | 'GIP' | 'GMD' | 'GNF' | 'GTQ' | 'GYD' | 'HKD' | 'HNL' | 'HRK' | 'HTG' | 'HUF' | 'IDR' | 'ILS' | 'IMP' | 'INR' | 'IQD' | 'IRR' | 'ISK' | 'JEP' | 'JMD' | 'JOD' | 'JPY' | 'KES' | 'KGS' | 'KHR' | 'KMF' | 'KPW' | 'KRW' | 'KWD' | 'KYD' | 'KZT' | 'LAK' | 'LBP' | 'LKR' | 'LRD' | 'LSL' | 'LTL' | 'LVL' | 'LYD' | 'MAD' | 'MDL' | 'MGA' | 'MKD' | 'MMK' | 'MNT' | 'MOP' | 'MRO' | 'MRU' | 'MUR' | 'MVR' | 'MWK' | 'MXN' | 'MYR' | 'MZN' | 'NAD' | 'NGN' | 'NIO' | 'NOK' | 'NPR' | 'NZD' | 'OMR' | 'PAB' | 'PEN' | 'PGK' | 'PHP' | 'PKR' | 'PLN' | 'PYG' | 'QAR' | 'RON' | 'RSD' | 'RUB' | 'RWF' | 'SAR' | 'SBD' | 'SCR' | 'SDG' | 'SEK' | 'SGD' | 'SHP' | 'SLL' | 'SLE' | 'SOS' | 'SRD' | 'STD' | 'SVC' | 'SYP' | 'SZL' | 'THB' | 'TJS' | 'TMT' | 'TND' | 'TOP' | 'TRY' | 'TTD' | 'TWD' | 'TZS' | 'UAH' | 'UGX' | 'UYU' | 'UZS' | 'VEF' | 'VES' | 'VND' | 'VUV' | 'WST' | 'XAF' | 'XCD' | 'XDR' | 'XOF' | 'XPF' | 'YER' | 'ZAR' | 'ZMK' | 'ZMW' | 'ZWL', required
  - `amount` string, required: Invoice amount (total value of the invoice in euros. If the currency is euro, `currency_amount` and `amount` are identical)
  - `currency_amount` string, required: Invoice currency amount (total value of the invoice in the currency of the invoice)
  - `currency_amount_before_tax` string, required: Invoice currency amount before tax (total value before tax of the invoice in the currency of the invoice)
  - `exchange_rate` string, required: Invoice exchange rate (used to convert the invoice to euros. If the invoice currency is euro it will be 1.0)
  - `date` string, date, nullable, required: Invoice issue date (ISO 8601)
  - `deadline` string, date, nullable, required: Invoice payment deadline (ISO 8601)
  - `performance_date` string, date, nullable, required: End date of the performance period of the first invoice line that has one (ISO 8601). Used for German VAT accounting (Leistungsdatum). Null if the company does not use German accounting, or if no invoice line has a performance period.
  - `currency_tax` string, required: Invoice taxable amount (in invoice currency)
  - `tax` string, required: Invoice taxable amount (in euros). If the currency is euro, `currency_tax` and `tax` are identical.
  - `language` 'fr_FR' | 'en_GB' | 'de_DE' | 'es_ES', required: The local default is based on the thirdparty (customer / supplier ) billing_language . In case the customer is not present, we will default to the company locale.
  - `paid` boolean, required: Invoice paid status (set to True if the invoice is paid)
  - `status` 'archived' | 'incomplete' | 'cancelled' | 'paid' | 'partially_paid' | 'partially_cancelled' | 'upcoming' | 'late' | 'draft' | 'credit_note' | 'proforma' | 'shipping_order' | 'purchasing_order' | 'estimate_pending' | 'estimate_accepted' | 'estimate_invoiced' | 'estimate_denied', required
  - `discount` object, required
    - `type` 'absolute' | 'relative', required: Discount type. - absolute if it is an amount - relative if it is a percentage
    - `value` string, required: Discount value on the total amount before tax of the line
  - `ledger_entry` object, required
    - `id` integer, required: Ledger entry identifier
  - `public_file_url` string, nullable, required: Public URL of the invoice file. The URL will expire after 30 minutes. May be null if the PDF has not been generated yet (for example right after creation or finalization); fetch the invoice again to get the URL once it is available.
  - `filename` string, nullable, required: Name of the file attached to the invoice. May be null immediately after creation if the PDF has not been generated yet; fetch the invoice again to get the filename once it is available.
  - `remaining_amount_with_tax` string, nullable, required: The remaining amount with VAT to pay for the invoice to be considered paid
  - `remaining_amount_without_tax` string, nullable, required: The remaining amount without VAT to pay for the invoice to be considered paid
  - `draft` boolean, required: Indicates if the invoice is in draft (has not been finalized)
  - `special_mention` string, nullable, required: Additional details
  - `sale_type` union, required: Type of sale printed on the invoice (Type de vente). `goods` is a supply of goods, `services` is a supply of services, and `goods_and_services` is both. `null` means the type has not been chosen. This is not invoice line `substance`.
    - 'goods' | 'services' | 'goods_and_services': Type of sale printed on a customer invoice. This is not invoice line substance.
    - unknown
  - `customer` object, nullable, required
    - `id` integer, required
    - `url` string, required: URL to get the customer.
  - `payment_method_ledger_account` object, nullable, required: Ledger account used for reconciliation by payment method. When present, the receivable was transferred to this account.
    - `id` integer, required
    - `url` string, required: URL to get the ledger account.
  - `invoice_line_sections` object, required
    - `url` string, required: URL to get the invoice line sections of the invoice.
  - `invoice_lines` object, required
    - `url` string, required: URL to get the invoice lines of the invoice.
  - `custom_header_fields` object, required
    - `url` string, required: URL to get the custom header fields of the invoice.
  - `categories` object, required
    - `url` string, required: URL to get the categories of the invoice.
  - `pdf_invoice_free_text` string, required
  - `pdf_invoice_subject` string, required
  - `pdf_description` string, nullable, required
  - `billing_subscription` object, nullable, required
    - `id` integer, required
  - `credited_invoice` object, nullable, required: The credited invoice if the invoice is a credit note.
    - `id` integer, required
    - `url` string, required: URL to get the credited invoice.
  - `customer_invoice_template` object, nullable, required
    - `id` integer, required
  - `transaction_reference` object, nullable, required: This reconciles the invoice with a transaction. See documentation about [automatic payment matching](https://pennylane.readme.io/v2.0/docs/automating-payment-matching).
    - `banking_provider` string, required: The banking provider for the transaction
    - `provider_field_name` string, required: Name of the field that you want to match
    - `provider_field_value` string, required: Value that you want to match
  - `payments` object, required
    - `url` string, required: URL to get the payments of the invoice.
  - `matched_transactions` object, required
    - `url` string, required: URL to get the transactions of the invoice.
  - `appendices` object, required
    - `url` string, required: URL to get the appendices of the invoice.
  - `installments` object, nullable, required: > ⚠️ **Warning**: This feature is in alpha > Until further rollout, this field will be `null` for all invoices. > If you plan to rely on it, please get in touch with us first.
    - `url` string, required: URL to get the installments of the invoice.
  - `quote` object, nullable, required: The quote at the origin of the invoice
    - `id` integer, required
  - `external_reference` string, required: The unique external reference that was assigned during creation either by you or Pennylane. (Same attribute as `external_id` in the API v1)
  - `purchase_order_reference` string, nullable, required: Buyer's purchase order reference (e-invoice field BT-13). Maximum 50 characters.
  - `contract_reference` string, nullable, required: Contract reference (e-invoice field BT-12). Maximum 50 characters.
  - `sales_order_reference` string, nullable, required: Seller's sales order reference (e-invoice field BT-14). Maximum 50 characters.
  - `e_invoicing` object, nullable, required: E-invoicing lifecycle information managed by the PA. Contains the current status and associated reason when applicable. This field is only present for invoices sent through e-invoicing.
    - `status` 'accepted' | 'approved' | 'collected' | 'in_dispute' | 'partially_collected' | 'refused' | 'rejected' | 'sent' | 'submitted', required
    - `reason` string, nullable, required
    - `flow` object, nullable, required: The AFNOR flow associated with this e-invoice.
      - `id` string, uuid, required
    - `lifecycle_events` object[], nullable, required: > ⚠️ **Warning**: This feature is in beta. > Until further rollout, this field will be `null` for all invoices. > If you plan to rely on it, please get in touch with us first. Chronologically ordered e-invoicing lifecycle events received from the PA. Some events are optional and only present when the receiving platform reports them.
      - `type` 'accepted' | 'available_to_buyer' | 'emitted_by_seller_platform' | 'in_dispute' | 'partially_collected' | 'received_by_buyer_platform' | 'refused' | 'rejected' | 'sent' | 'submitted', required
      - `timestamp` string, date-time, required
  - `factur_x` boolean, required: Whether the attached invoice file is a Factur-X document (a PDF/A-3 with an embedded structured XML).
  - `schematron_validation_status` 'pending' | 'valid' | 'invalid', nullable, required: Result of Schematron structural validation for Factur-X invoices. Only relevant when `factur_x` is true, null otherwise.
  - `archived_at` string, date-time, nullable, required: The time the invoice has been archived
  - `created_at` string, date-time, required: The time the invoice has been created
  - `updated_at` string, date-time, required: The last time the invoice has been updated

## Other responses

- `400`: Bad request
- `401`: Access token is missing or invalid
- `403`: Access to this resource forbidden
- `404`: The resource was not found
- `422`: Unprocessable content

## Changes

- **2026-11-03** `871f863307e5`: 2 warning, 61 info
  - added the new `VES` enum value to the `currency` response property for the response status `201`
  - added the new `es_ES` enum value to the `language` response property for the response status `201`
  - added the new optional `header` request parameter `X-Company-Id`
  - added the new optional request property `anyOf[subschema #1: Draft Customer Invoice]/contract_reference`
  - …59 more

[Operation history](https://skmtc.dev/pennylane/apis/company-v2/changes/api/external/v2/customer_invoices/post.md)

---

[API](https://skmtc.dev/pennylane/apis/company-v2.md) - [All operations](https://skmtc.dev/pennylane/apis/company-v2/llms.txt) - [OpenAPI document](https://skmtc.dev/pennylane/apis/company-v2/revisions/871f863307e5?raw)
