Skip to content

Prestaties upload

POST Upload a CSV file with prestaties (billing records of add-on medicines) to Pharma-Insights.

Institutions that use Pharma-Insights can deliver their billing records straight from their own systems (HIS, EHR, data warehouse). This is the API counterpart of the manual upload in Insights. It is a REST API with a single endpoint and a single action.

The file is validated on receipt and processed asynchronously. The response contains the per-row validation result; further processing (unit conversion, start-stop analysis, dashboards) happens in the background and is visible in the upload history in Insights.

Access

Available to institutions with a Pharma-Insights licence only. Request an API key via vragen@pharma-insights.nl. A test environment is not offered by default; contact us if you need one for your implementation.

Endpoint

POST https://www.pharma-insights.nl/api/prestaties

Requests are POST requests with the CSV content as the raw body (no multipart upload, no JSON). Other HTTP methods are rejected with 405.

File format

  • No header row. A header row is reported as an invalid row and skipped.
  • Delimiter: ; (recommended), , or tab. The character that occurs most often in the first line is used for the whole file.
  • Encoding UTF-8; a UTF-8 BOM is accepted.
  • Empty lines are skipped.
  • Use a single date format throughout the file. YYYY-MM-DD is recommended.
  • Quantities are units (pieces) by default. If you deliver packages or the HiX purchase quantity, say so with the x-aantallen-in header (see below).

The columns, in order:

# Column Required Notes
1 prestatie_id yes Unique number of the billing record. Digits only, at most 18 digits.
2 patient_id yes Pseudonymised patient identifier (text). Never a citizen service number or a name.
3 indicatie_id yes G-Standaard indication id (file indicaties bij supplementaire producten).
4 agb_code yes AGB code of the medical specialty, e.g. 313 (internal medicine) or 324 (rheumatology). Must exist in the NZa care typing (zorgtypering).
5 zindex_nummer yes Z-Index number (8 digits) of an add-on product with a billing title.
6 aantal_eenheden yes Quantity in the unit given by x-aantallen-in (units by default), non-zero. Decimal separator , or ..
7 uzovi_code yes UZOVI code of the health insurer.
8 uitvoerings_datum yes Date of administration/dispensing, YYYY-MM-DD. May not be in the future.
9 zorgtypering_code yes NZa care typing component valid for the given agb_code.
10 opmerkingen no Free text.
11 arts_code no Free text, e.g. the prescriber's AGB code.
12 postcode no Four digits of the patient's postal code, or empty.
13 muraliteit no intramuraal (default) or extramuraal.

Required columns must always be present; optional columns may be omitted (a row then has 9 columns) or left empty.

Authentication

The institution is identified by two headers. There is no HMAC and no IP whitelisting, so treat the API key as a secret.

Header Notes
x-picode The PI-Code of your institution.
x-apikey The API key issued to your institution.
x-aantallen-in Optional. Unit of aantal_eenheden: stuk (default), verpakking or inkoophoeveelheid. See Unit of quantities.
content-type text/csv

Unit of quantities (x-aantallen-in)

Insights converts all quantities to packages. The x-aantallen-in header tells us which unit your file uses; it applies to the whole file.

Value Meaning
stuk (default) Number of counting units, e.g. tablets, vials or syringes. Divided by the package content from the G-Standaard.
verpakking Number of packages. No conversion.
inkoophoeveelheid Purchase quantity as in a HiX extract, where the package content of some products (e.g. oral solutions in ml) is defined differently. Divided by the purchase quantity from the G-Standaard.

An unknown value yields a 400. The last unit used is remembered and preselected in the manual upload in Insights.

Request

curl -X POST https://www.pharma-insights.nl/api/prestaties \
  -H "x-picode: 871001" \
  -H "x-apikey: <your-api-key>" \
  -H "x-aantallen-in: stuk" \
  -H "content-type: text/csv" \
  --data-binary @prestaties.csv

Example prestaties.csv with the required columns only:

900000001;P-8f3a2c;1234;313;12118249;2;3311;2026-06-15;0
900000002;P-8f3a2c;1234;313;12118249;2;3311;2026-07-13;0
900000003;P-51be09;1234;324;15239876;1;7029;2026-07-14;0

With optional columns:

900000004;P-51be09;1234;324;15239876;1;7029;2026-08-11;0;;01012345;3511;intramuraal

Response

Code Meaning
200 File received and queued for processing. validation lists the rejected rows (may be empty).
400 Empty body, invalid x-aantallen-in, or no valid row in the file.
401 x-picode or x-apikey missing, or not matching an active institution.
405 HTTP method other than POST.
503 The API is temporarily disabled. Retry later.

All error responses are JSON.

Example response for a processed request in which one row was rejected:

{
  "result": "success",
  "message": "Bestand succesvol ontvangen en in verwerking.",
  "validation": [
    {
      "columnIndex": 4,
      "columnNumber": 5,
      "value": 14321976,
      "message": "Nummer is geen geldig Z-Index nummer voor een add-on product. Het artikel dient een declaratietitel te hebben (gehad).",
      "rowNumber": 3,
      "rowIndex": 2
    }
  ]
}

Example response when no row is valid:

{
  "result": "error",
  "message": "Bestand bevat geen geldige rijen.",
  "validation": [
    {
      "columnIndex": 0,
      "columnNumber": 1,
      "value": "",
      "message": "Niet genoeg kolommen in de rij. Verwacht minimaal 9 kolommen. Gevonden: 3 kolommen.",
      "rowNumber": 1,
      "rowIndex": 0
    }
  ]
}

Example response for an authentication failure:

{
  "result": "error",
  "error": "Ongeldige of ontbrekende x-picode/x-apikey"
}

Messages are in Dutch.

Fields

Field Type Description
result string success or error.
message string Explanation of the result.
error string Error message; only present for errors without row validation (empty body, authentication, 405, 503).
validation object[] Rejected rows. Empty when all rows are valid.
validation[].rowNumber integer Line number in the file (1-based).
validation[].rowIndex integer Line index (0-based).
validation[].columnNumber integer Column number (1-based).
validation[].columnIndex integer Column index (0-based).
validation[].value mixed The supplied value after normalisation.
validation[].message string Reason for rejection.

Points of attention

Check validation even on a 200. Rejected rows are not processed; the remaining rows are. Correct the rejected rows and submit them again.

Check the unit of your quantities. Without x-aantallen-in the quantities are read as units; a file in packages would then yield far too low quantities.

Processing happens in the background. The status and the number of processed rows are shown in the upload history in Insights.

Questions about onboarding, the API key or the file format: vragen@pharma-insights.nl.