Skip to content

GIP upload

Draft

This API does not exist yet. This document is a draft specification that we provide for alignment, so you can prepare your data format for it. Endpoints, columns, headers and responses may still change during implementation. Do not build a production integration based on this document without alignment with Pharma-Intelligence.

POST Upload a GIP price list (wholesaler purchase prices) to PharmaPortal.

Users of PharmaPortal can upload a GIP price list to PharmaPortal from their own system via an API. This is the API variant of the "GIP toevoegen" (add GIP) function in PharmaPortal. This is a REST API with a single endpoint and a single possible action.

A GIP price links a price for a wholesaler to an item (Z-Index number) for a given month. One upload concerns exactly one wholesaler and one month, which you provide via the headers x-portal-groothandel and x-portal-maand. The period (start and end date) is derived by PharmaPortal from that month; you therefore do not put dates in the rows. A price applies only within the specified month: a month without an upload has no GIP price, there is no automatic carry-over to a following month. Each row is uniquely identified by the combination wholesaler + month + Z-Index within your organisation.

Access

Available to PharmaPortal licence holders only.

Endpoint

POST https://demo.pharma-portal.nl/api/gip/upload
POST https://www.pharma-portal.nl/api/gip/upload

Requests are POST requests with the CSV content directly as the body (so no multipart file or JSON). The CSV file contains four columns without a header row. You provide the wholesaler and the month once via the headers x-portal-groothandel and x-portal-maand; these are therefore not in the rows. Both , and ; are recognised as separators. The columns are, in order:

# Column Description
1 zindex_nummer Z-Index number (8 digits).
2 soort vast, percentage or afslag.
3 prijs For vast: the fixed price per package (excl. VAT). For afslag: the discount amount relative to AIP. Empty for percentage.
4 percentage For percentage: discount percentage relative to AIP (0–100). Empty for vast/afslag.

For afslag and percentage the final price is calculated server-side from the item's AIP (just as in the "GIP toevoegen" function).

Authentication

This API uses (identical to the other PharmaPortal APIs):

  • IP whitelisting for security
  • An API key for authentication & rate limiting
  • HMAC for integrity verification (mandatory for POST)

The API key determines on behalf of which PharmaPortal organisation the GIP list is written (the portal_klant in the unique key). You do not need to send this.

Header Description
x-portal-key The API key issued to your organisation.
x-portal-hmac Hexadecimally encoded SHA-512 HMAC of the request body (the raw CSV), computed with your API secret.
x-portal-groothandel PI-code of the wholesaler this upload applies to (mandatory). One upload concerns one wholesaler. The value must be a known, active wholesaler.
x-portal-maand The month the prices apply to, format YYYYMM (e.g. 202607 for July 2026) — mandatory. The start and end date of all rows are derived from it.
x-portal-on-exist Determines what happens for an already existing row with the same key. Can be error (default), overwrite or skip. See Collisions below.
content-type text/csv

Request

curl -X POST https://demo.pharma-portal.nl/api/gip/upload \
  -H "x-portal-key: <your-api-key>" \
  -H "x-portal-hmac: <sha-512-hmac>" \
  -H "x-portal-groothandel: 671234" \
  -H "x-portal-maand: 202607" \
  -H "x-portal-on-exist: error" \
  -H "content-type: text/csv" \
  --data-binary @gip.csv

The examples below assume the headers x-portal-groothandel: 671234 and x-portal-maand: 202607 (July 2026). The prices therefore apply to that wholesaler and that month.

1. Simple list with fixed prices — the most common upload: one fixed price (excl. VAT) per item for the specified month.

12345678;vast;100.01;
34567890;vast;14.31;
56789012;vast;53.23;
78901234;vast;782.21;

2. Mixed types — fixed price, discount percentage relative to AIP and a discount amount relative to AIP mixed together. Note the empty columns (prijs empty for percentage, percentage empty for vast/afslag).

12345678;vast;100.01;
34567890;percentage;;12.5
56789012;afslag;5.00;

3. Comma as separator — also permitted (instead of ;).

12345678,vast,100.01,

Collisions (x-portal-on-exist)

A row already exists when a GIP price is already present in PharmaPortal for this wholesaler + month + zindex_nummer (within your organisation). The behaviour is determined by the header x-portal-on-exist:

Value Behaviour
error (default) The colliding row is not imported and appears in errors.
overwrite The existing row is updated with the supplied price data.
skip The existing row is left unchanged; the supplied row is skipped (counts as a warning).

Rows that do not collide are always added. This API never deletes rows that are not in the upload — it is an upsert per row, not a full replacement of your GIP list.

Response

Code Meaning
200 For a processed request (even when individual rows contain errors).
401 For invalid authentication, HMAC or IP.

Example of a response for a successful & correct request:

{
  "result": "success",
  "data": {
    "numRowsTotal": 4,
    "numRowsImported": 2,
    "numRowsError": 1,
    "numRowsWarning": 1,
    "warnings": [
      { "line": 2, "message": "Regel overgeslagen: bestaat al (skip)." }
    ],
    "errors": [
      { "line": 4, "message": "Onbekend Z-Index nummer: 14321976" }
    ]
  }
}

Example of a response for a processing/request error:

{
  "result": "error",
  "errorMessage": "Ongeldige waarde voor x-portal-on-exist. Toegestaan: error, overwrite, skip"
}

Fields

Field Type Description
result string success or error.
data.numRowsTotal integer Number of rows supplied.
data.numRowsImported integer Number of rows processed successfully.
data.numRowsError integer Number of rows with an error (not imported).
data.numRowsWarning integer Number of rows with a warning (e.g. skipped).
data.warnings object[] Warnings per row (line, message).
data.errors object[] Errors per row (line, message).

Notes

The HMAC must be computed over the exact CSV bytes of the request body.

A maximum file size of 10 MB applies per upload. You can split very large lists into multiple requests (guideline: at most approx. 50,000 rows per request).

Want to test your integration? Contact us in good time at info@zagis.nl for test data and an API key.