Skip to content
Documentation
English
Open the app

Push a purchase invoice

Step-by-step use case to send a purchase invoice with its PDF to the NovaFisko importer, have it analysed, validate it and book it.

You have a supplier invoice in PDF, image or XML format (UBL, Peppol BIS). This guide uploads it to the importer, triggers the analysis, then validates it to create the document and its entry. It is exactly the flow of the Documents tab of the application.

Prerequisites: a token with the read and write abilities, and the public_token of the company.

The life cycle of an import follows these statuses:

Status Meaning
queued File received, waiting for analysis
analyzing Analysis in progress
ready Analysis finished, reliable data
needs_review Analysis finished, but one point needs checking
duplicate The file or the invoice already exists in the company
error The analysis failed and must be rerun
validated Document created, import finished
expanded ZIP archive unpacked into child imports

Step 1: upload the file

The upload uses multipart/form-data. The field is called files[] and accepts up to 20 files of 25 MB each.

curl -X POST https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/document-imports \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN" \
  -H "Accept: application/json" \
  -H "X-Client-Mutation-Id: 9a7d1a0c-2b1f-4d0e-bb0d-6d5a3d7f2c41" \
  -F "files[]=@/chemin/vers/F-2026-0918.pdf" \
  -F "batch_id=3f5c2b9e-8f0a-4f6a-9a0e-1b7b2a6f4c10"
Field Required Description
files[] yes 1 to 20 files. Extensions: pdf, jpg, jpeg, png, heic, heif, webp, gif, xml, zip
batch_id no UUID of your choice to group several uploads. Generated if absent

Response 201:

{
  "batch_id": "3f5c2b9e-8f0a-4f6a-9a0e-1b7b2a6f4c10",
  "imports": [
    {
      "id": 5120,
      "company_id": 318,
      "batch_id": "3f5c2b9e-8f0a-4f6a-9a0e-1b7b2a6f4c10",
      "original_name": "F-2026-0918.pdf",
      "mime": "application/pdf",
      "size": 84213,
      "kind": "pdf",
      "status": "queued",
      "progress": 0,
      "extracted": null,
      "warnings": null,
      "file_url": "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/document-imports/5120/file?expires=1791190000&preview=1&signature=...",
      "has_preview": false,
      "version": 1
    }
  ]
}

A ZIP archive produces a parent import with the expanded status and one import per contained file, 50 at most. A file whose extension is not accepted makes the whole upload fail with 422.

Step 2: run the analysis

The analysis is synchronous: the call responds when it is finished. Allow a timeout of at least 150 seconds on the client side.

curl -X POST https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/document-imports/5120/process \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN" \
  -H "Accept: application/json" \
  --max-time 180
{
  "id": 5120,
  "original_name": "F-2026-0918.pdf",
  "kind": "pdf",
  "status": "ready",
  "progress": 100,
  "step": "done",
  "engine": "api",
  "suggested_direction": "purchase",
  "suggested_third_party_id": 41,
  "suggested_third_party": {"id": 41, "code": "BRASSCOL", "name": "Brasserie des Collines SA", "type": "supplier", "vat_number": "BE0999900134"},
  "extracted": {
    "document_type": "invoice",
    "direction": "purchase",
    "counterparty": {
      "name": "Brasserie des Collines SA",
      "vat_number": "BE0999900134",
      "iban": "BE71096123456769",
      "bic": "GKCCBEBB"
    },
    "number": "F-2026-0918",
    "date": "2026-10-02",
    "due_date": "2026-11-01",
    "structured_communication": "+++091/8202/60018+++",
    "currency": "EUR",
    "lines": [
      {"description": "Fûts 20 L blonde", "quantity": 10, "unit_price": 125, "vat_rate": 21, "amount_net": 1250, "amount_vat": 262.5, "amount_gross": 1512.5}
    ],
    "totals": {"net": 1250, "vat": 262.5, "gross": 1512.5, "vat_breakdown": [{"rate": 21, "base": 1250, "amount": 262.5}]},
    "payment": {"iban": "BE71096123456769", "bic": "GKCCBEBB", "paid": false},
    "nature": null,
    "confidence": 0.94,
    "language": "fr"
  },
  "warnings": [],
  "error": null,
  "duplicate_of_import_id": null,
  "duplicate_of_document_id": null,
  "imported_document_id": null,
  "file_url": "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/document-imports/5120/file?expires=...&signature=...",
  "has_preview": false
}
Note

In extracted, amounts are JSON numbers and not strings: this block reflects what was read on the document, before booking. The entries created afterwards follow the decimal string convention.

If you do not call process, a scheduled job analyses the queued imports every minute. You can then simply poll the list:

curl "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/document-imports?batch_id=3f5c2b9e-8f0a-4f6a-9a0e-1b7b2a6f4c10&status=ready,needs_review,error,duplicate" \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN"

A UBL XML file is read directly, without analysis by artificial intelligence. The result is immediate and exact.

Step 3 (optional): correct the data

When the status is needs_review, read warnings: each warning carries a code (counterparty_missing, date_missing, totals_missing, totals_mismatch...) and a message. Correct the sheet without validating:

curl -X PATCH https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/document-imports/5120 \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"extracted": {"number": "F-2026-0918", "date": "2026-10-02", "due_date": "2026-11-01"}}'

Send the complete extracted sheet as you want it: NovaFisko normalises it again and recalculates the totals.

Step 4: validate and book

Validation creates the document, attaches it to a third party and, with book: true, posts the entry to the purchase journal.

curl -X POST https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/document-imports/5120/validate \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Client-Mutation-Id: 1c7f5e2a-90c4-4a55-8f0b-5f6e6a3d9b72" \
  -d '{
    "direction": "purchase",
    "third_party_id": 41,
    "lines": [{"account_id": 118, "vat_code_id": 12}],
    "book": true,
    "push_to_novadesko": false
  }'
Field Description
third_party_id Existing third party of the company. Failing that, the suggested third party is used
new_third_party Creates the third party on the fly: name required, then type, vat_number, enterprise_number, address, postal_code, city, country, iban, bic, email, phone
direction purchase or sale. By default, the detected direction
lines One item per line of the document, in the same order: account_id and vat_code_id. Failing that, the suggestions of the analysis are used
extracted Corrected sheet, if you did not go through step 3
book true to also create the accounting entry. false by default: the document waits in the Documents tab
push_to_novadesko Sends the locked document to Novadesko. true by default only for a company imported from Novadesko
force true to validate despite the duplicate status

Response 201:

{
  "import": {"id": 5120, "status": "validated", "imported_document_id": 7741, "progress": 100},
  "document": {
    "id": 7741,
    "type": "purchases",
    "direction": "purchase",
    "number": "F-2026-0918",
    "document_date": "2026-10-02T00:00:00.000000Z",
    "status": "booked",
    "third_party": {"id": 41, "name": "Brasserie des Collines SA", "type": "supplier", "code": "BRASSCOL"},
    "lines": [
      {
        "id": 19022,
        "description": "Fûts 20 L blonde",
        "actual_account": {"id": 118, "number": "604000", "label": "Achats de marchandises"},
        "vat_code": {"id": 12, "code": "A21", "rate": "21.00"}
      }
    ]
  },
  "entry": {
    "id": 1842,
    "number": 212,
    "entry_date": "2026-10-02T00:00:00.000000Z",
    "reference": "F-2026-0918",
    "status": "posted",
    "journal": {"id": 3, "code": "ACH"},
    "lines": [
      {"id": 5521, "debit": "1250.00", "credit": "0.00", "account": {"id": 118, "number": "604000", "label": "Achats de marchandises"}},
      {"id": 5522, "debit": "262.50", "credit": "0.00", "account": {"id": 77, "number": "411000", "label": "TVA à récupérer"}},
      {"id": 5523, "debit": "0.00", "credit": "1512.50", "account": {"id": 90, "number": "440000", "label": "Fournisseurs"}}
    ]
  },
  "novadesko": {"status": "skipped", "document_id": null, "token": null, "locked": false, "error": null, "message": null}
}

With book: false, entry is null and the document remains to be booked.

Variant: record the entry directly

If you already have the structured data and do not need to keep the PDF, post the entry in a single call. NovaFisko calculates the VAT and the third-party line.

curl -X POST https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/entries/invoice \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Client-Mutation-Id: 0b0f7a52-63f4-4f1f-8a43-0d4f6b0b8a10" \
  -d '{
    "journal_id": 3,
    "third_party_id": 41,
    "entry_date": "2026-10-02",
    "due_date": "2026-11-01",
    "reference": "F-2026-0918",
    "lines": [
      {"account": "604000", "amount": "1250.00", "vat_code": "A21", "label": "Fûts 20 L blonde"}
    ]
  }'

The amount of each line is exclusive of VAT. The journal type (purchase or sale) determines the direction of the entry.

Common errors

Status Cause Fix
422 at step 1 Extension not accepted or file larger than 25 MB Convert or split the file
422 at step 2 Import already validated Nothing to do, read imported_document_id
422, field status at step 4 Import not analysed yet, or duplicate without force Call process, or send force: true after checking
422, field lines.0.account_id Account or VAT code missing or not part of the company Provide an id from the company
422, code period_locked The date falls in a locked period See Periods
429 More than 30 uploads per minute Group the files, 20 per upload
Tip

Subscribe a webhook to the document.imported and document.booked events to be notified when an analysis finishes and when the document is booked, without polling the list.

See also