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¶
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.
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).
3. Comma as separator — also permitted (instead of ;).
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.