Records invoices billed by an external system.

POST /accounting/invoices/import

Group: Accounting › Invoices · Operation ID: importInvoices

Records invoices that another system decided, against a sales order flagged for externalized billing. The response contains only the ids of the invoices created, in the same order as the entries you sent, so entry N and id N are the same invoice. Read each one back with GET accounting/invoices/:id.

You supply the grouping, each line's total and the tax. This path calls no tax engine. It resolves each line to its invoice-plan line by salesOrderProductLineId and plannedDate, creating one where none exists and the schedule is still open, then creates the invoices exactly as you grouped them. Two consequences follow. A tax-exempt line sends an empty taxLines array rather than omitting it. Any one-time discount must already be netted into each line's totalPrice, because the built-in discount allocation is skipped for externalized sales orders.

This endpoint serves only externalized sales orders, ones whose invoices are decided elsewhere. A sales order whose billing is scheduled in Everest is refused with SALES_ORDER_NOT_EXTERNALISED, because its invoices are created by the built-in billing run, and there is no API endpoint for that. Which applies is a property of the sales order, not a choice.

The call runs in one transaction. If any entry fails, no invoice from the batch is recorded.

Open in the interactive reference

Parameters

Name In Type Required Description
Api-Version header "v1" yes The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version v1.
Idempotency-Key header string no An opaque caller-chosen string (1-255 characters) that makes this request safe to retry. Repeating the same key with an identical request body replays the original response instead of re-executing - but only once that original request succeeded; a failed attempt re-executes on retry. Repeating the key with a different body is answered with 422. A key still in flight is answered with 409 - as is a key whose original request was interrupted before it finished, for a few minutes afterwards, until that attempt is presumed dead. A completed response stays replayable for 24 hours. The key is scoped to the caller, not to the action: reusing it for a different action is answered with 409 or 422 rather than treated independently. On read actions this header is ignored. On write actions that cannot offer the guarantee it is answered with 400 IDEMPOTENCY_NOT_SUPPORTED rather than silently ignored.

Request body

Required, application/json: importInvoicesInput.

Field Type Required Description
salesOrderId string yes The sales order these invoices bill. It must be flagged for externalized billing. One whose billing is scheduled in Everest is refused with SALES_ORDER_NOT_EXTERNALISED. See id on GET accounting/sales-orders/:id.
invoices array of object yes The invoices to record, one entry each, exactly as the source system grouped them. Every entry yields one invoice, and the ids come back in this order.
invoices[].externalInvoiceId string no The id of this invoice in the source system, stamped on the created invoice for reconciliation.
invoices[].invoiceDate string (date) yes The date to stamp on this invoice. Format YYYY-MM-DD.
invoices[].lines array of object yes The lines of this invoice. Each resolves to one invoice-plan line by salesOrderProductLineId and plannedDate.
invoices[].lines[].salesOrderProductLineId string yes The unique identifier for the sales-order product line this invoice line bills against. There is no endpoint that returns a single sales-order product line.
invoices[].lines[].plannedDate string (date) yes The planned billing date of the target invoice-plan line. Format YYYY-MM-DD. When no plan line exists for this date and the schedule is still open, one is created using this as both its service start date and its invoice date.
invoices[].lines[].serviceEndDate string (date) no The last day of the service period, for a plan line created on an open schedule. Format YYYY-MM-DD. Ignored when the line matches an existing plan line.
invoices[].lines[].totalPrice string (decimal) yes The pre-tax line total, in the sales order's currency. It must match the resolved plan line's total price. Any one-time discount must already be netted in.
invoices[].lines[].dutiesAndCustomsAmount string (decimal) no The duties and customs charged on this line, in the sales order's currency. Requires the entity's Duties and Customs feature to be enabled.
invoices[].lines[].taxAmount string (decimal) no The total tax on this line, in the sales order's currency. When given, it must equal the sum of taxLines[].amount. When omitted, it is computed from that sum.
invoices[].lines[].taxCode string no The line-level tax code, as the source tax engine issued it.
invoices[].lines[].taxDate string (date) no The date the line's tax was determined on. Format YYYY-MM-DD. Typically the service end date or the invoice date.
invoices[].lines[].taxExemptCode string no The exempt code applied to this line.
invoices[].lines[].exceptionNumber string no The exception number for the tax exemption, as the source tax engine issued it.
invoices[].lines[].taxMode string, one of "TaxInclusive", "TaxExclusive" no Whether totalPrice already includes tax.
invoices[].lines[].taxLines array of object yes The per-jurisdiction tax for this line. You supply it, because no tax engine is called on this path. Send an empty array for a tax-exempt line.
invoices[].lines[].taxLines[].name string yes The name of the tax as it should appear on the document, for example 'CA Sales Tax' or 'VAT'.
invoices[].lines[].taxLines[].amount string (decimal) yes The tax amount for this jurisdiction, in the sales order's currency.
invoices[].lines[].taxLines[].rate string (decimal) no The tax rate as a decimal fraction. For example, 0.21 is 21%. A rate, not an amount, so it has no currency.
invoices[].lines[].taxLines[].taxableAmount string (decimal) no The pre-tax amount the rate was applied to, in the sales order's currency.
invoices[].lines[].taxLines[].exemptAmount string (decimal) no The portion of the taxable base that was exempted, in the sales order's currency.
invoices[].lines[].taxLines[].taxType string no The engine classification of the tax, for example 'Sales' or 'VAT'.
invoices[].lines[].taxLines[].rateType string no The VAT rate classification, for example 'Standard', 'Reduced' or 'Zero'.
invoices[].lines[].taxLines[].vatCode string no The VAT code for this jurisdiction.
invoices[].lines[].taxLines[].isItemTaxable boolean no Whether the item is taxable in this jurisdiction.
invoices[].lines[].taxLines[].taxTreatment string, one of "salesTax", "domesticStandardRate", "domesticReducedRate", "domesticSalesZeroRated", "domesticSalesExempt", "vatIntraEuStandardRate", "vatIntraEuReducedRate", "nonEuExempt", "reverseCharge" no The VAT treatment for this jurisdiction. When supplied, the built-in VAT determination is bypassed.

Example:

{
  "salesOrderId": "8c1f4a92-3e77-4d21-9b05-6a2f1c8e4d33",
  "invoices": [
    {
      "externalInvoiceId": "NS-INV-88213",
      "invoiceDate": "2026-09-01",
      "lines": [
        {
          "salesOrderProductLineId": "b2d7f309-6c14-4a85-9f37-0e8c5d1b7a26",
          "plannedDate": "2026-09-01",
          "serviceEndDate": "2026-09-30",
          "totalPrice": "1000.00",
          "taxAmount": "210.00",
          "taxCode": "NL-VAT-STD",
          "taxMode": "TaxExclusive",
          "taxLines": [
            {
              "name": "NL VAT",
              "amount": "210.00",
              "rate": "0.21",
              "taxableAmount": "1000.00",
              "taxType": "VAT",
              "rateType": "Standard",
              "taxTreatment": "domesticStandardRate"
            }
          ]
        }
      ]
    }
  ]
}

Response

200 Success

Under data (importInvoicesOutput):

Field Type Required Description
ids array of string yes The ids of the invoices recorded, one per requested entry and in the same order. Read each back with GET accounting/invoices/:id.

Response headers

Errors

Code Status
SALES_ORDER_NOT_FOUND 400
SALES_ORDER_NOT_EXTERNALISED 400
SALES_ORDER_NOT_APPROVED 400
NO_INVOICES_REQUESTED 400
NO_LINES 400
IDEMPOTENCY_KEY_CONFLICT 409
IDEMPOTENCY_PAYLOAD_MISMATCH 422

Statuses