Posting sales & purchase invoices

Push invoices and credit notes, with or without their PDF, as book entries.

📘

Conventions

In the examples, $API_URL stands for the api_url of the connected license and $ACCESS_TOKEN for a valid access token. See Quickstart.

Sales and purchase invoices pushed through the API are converted into book entries in the corresponding daybook. The response contains the generated book entry's Id.

ActionSalesPurchases
Createinvoices.sales.newinvoices.purchases.new
Updateinvoices.sales.updateinvoices.purchases.update

Before you start

You need:

  1. the FolderId,
  2. the DaybookId of a sales or purchase daybook (daybooks.list, types 200/250 for sales and 100/150 for purchases),
  3. the CompanyId of the customer or supplier, found or created as described in Managing customers & suppliers,
  4. the search keys of the accounts to book each line on (accounts.list), e.g. 700000 for sales or 612000 for purchases.

Create a sales invoice

{
  "FolderId": "83f26e75-f474-4b09-a1d3-aa698e18fbf0",
  "DaybookId": "87f48c7e-54d1-48d2-aed7-447e6003bc67",
  "Type": 0,
  "Number": 202409001,
  "Date": "2024-09-04T00:00:00+00:00",
  "DueDate": "2024-10-04T00:00:00+00:00",
  "CompanyId": "32ebe925-23cc-4a3e-8b36-8b2b33780fc1",
  "TotalAmount": 1210,
  "BaseAmount": 1000,
  "TaxAmount": 210,
  "PaymentReferences": "+++040/7139/58328+++",
  "Comment": "Invoice 2024-09-001",
  "InvoiceLines": [
    {
      "Account": "700000",
      "BaseAmount": 1000,
      "TaxAmount": 210,
      "TaxRate": 21,
      "TaxOrigin": 0,
      "TaxType": 0,
      "Comment": "Consulting services"
    }
  ]
}
{ "Id": "0d6822be-8559-488a-b348-eea0dd4a735b" }

Type is 0 for an invoice and 1 for a credit note.

Amount rules

The API checks that the invoice is consistent:

  • TotalAmount = BaseAmount + TaxAmount;
  • the sum of the lines' BaseAmount = the invoice's BaseAmount;
  • the sum of the lines' TaxAmount = the invoice's TaxAmount.

Two options let you relax these checks when needed:

OptionDefaultEffect
OverrideTaxAmountsfalseTax amounts are recalculated (base × rate) and adapted when the provided amount is within 1 cent. Set to true to force your own tax amounts.
AllowUnbalancedfalseUnbalanced book entries are refused. Set to true to force the entry even though it is not balanced.

VAT on invoice lines

Each line carries its VAT treatment through a combination of fields:

FieldSalesPurchases
TaxRate✔✔
TaxType (0 National, 1 European, 2 International)✔✔
TaxOrigin✔✔
TaxKind (0 Merchandises, 1 Goods & services, 2 Investments)✔
TaxCondition / TaxConditionValue✔
TaxCountryCode (OSS lines only, TaxOrigin = 13)✔

Only some combinations are valid. The accepted combinations are listed in these reference files:

Purchase-specific options

Purchase invoices support a few additional fields:

  • VehicleId, at invoice or line level: associates a vehicle with lines whose account requires one;
  • PersonalShare on a line: the private portion of the expense, as a percentage of the line's total (base + tax) and the corresponding amount.
"InvoiceLines": [
  {
    "Account": "612000",
    "BaseAmount": 1000,
    "TaxAmount": 210,
    "TaxRate": 21,
    "TaxType": 0,
    "TaxKind": 0,
    "TaxCondition": 1,
    "TaxConditionValue": "true",
    "TaxOrigin": 2,
    "PersonalShare": { "PersonalSharePercentage": 50, "PersonalShareAmount": 605.0 }
  }
]

Optional features

FeatureFieldsNotes
Payment informationPaymentReferences, PaymentModeE.g. a structured communication +++040/7139/58328+++.
Cash discountDiscountRate, amount and deadline. If no date is given, 7 days are added to the invoice date.
Foreign currencyCurrencyCode, CurrencyRatenull means EUR. The folder must be configured to allow currencies. If no rate is given, the rate of the day is used.
MatchingMatchNoPre-assign a matching number (see Outstanding items & matching).
AnalyticsCostLines or CostDistributionKey per lineThe sum of a line's cost lines must equal its BaseAmount. If both are provided, cost lines take precedence.

Confirmation and numbering

Confirmed is false by default: the invoice is created as an unconfirmed entry that the accountant can review in Horus Office. Number is the invoice number associated with the book entry. It can be 0 when the invoice is not confirmed.

Attaching the invoice document

To send the invoice's PDF (or image/XML) together with the data, use multipart/form-data with two fields, file and body, and set FileName:

curl -X POST "$API_URL/invoices.purchases.new" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -F "[email protected]" \
  -F 'body={
        "FolderId": "83f26e75-f474-4b09-a1d3-aa698e18fbf0",
        "DaybookId": "9d0c7b6a-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
        "Type": 0,
        "Number": 0,
        "Date": "2024-09-04T00:00:00+00:00",
        "DueDate": "2024-10-04T00:00:00+00:00",
        "CompanyId": "32ebe925-23cc-4a3e-8b36-8b2b33780fc1",
        "TotalAmount": 121,
        "BaseAmount": 100,
        "TaxAmount": 21,
        "FileName": "supplier-invoice-2024-118.pdf",
        "InvoiceLines": [
          { "Account": "612000", "BaseAmount": 100, "TaxAmount": 21, "TaxRate": 21,
            "TaxType": 0, "TaxKind": 0, "TaxCondition": 1, "TaxConditionValue": "true", "TaxOrigin": 2 }
        ]
      }'

See Documents & attachments for details.

Updating an invoice

invoices.sales.update and invoices.purchases.update take the BookEntryId of the invoice plus the complete invoice payload (same required fields as creation):

  • the response contains the newly generated book entry's Id: replace the one stored on your side;
  • the original attachment is deleted in both cases. Send the document again with multipart/form-data if it should be kept.
🚧

Updates are full replacements

Unlike master data updates (companies, accounts…), invoice updates are not partial: send the full invoice as it should be after the update.


Did this page help you?