Contracts upload¶
Draft
This specification is not final. This API does not exist yet; this document is a draft specification that we provide for alignment so you can prepare your data format. Endpoints, columns, headers and responses may still change during implementation. Do not build a production integration based on this document without aligning with Pharma-Intelligence.
POST Import (upload) contracts from your own system into PharmaPortal.
Users of PharmaPortal can import (upload) contracts into PharmaPortal from their own system via an API. This is the API variant of the "Add contract" upload function in PharmaPortal. Each contract links a price agreement per article (Z-Index number) to a customer (PI code), valid over a period. Contracts are written under your organisation. This is a REST API with a single endpoint and a single possible action.
Access
Available to PharmaPortal licence holders only.
Endpoint¶
See also Contracts at reference date for reading active contracts.
Request body¶
Requests are POST requests with the CSV content directly as the body (so no
multipart file or JSON). The CSV file contains thirteen columns without a header
row. Both , and ; are recognised as separators. The columns are, in order:
| # | Column | Description |
|---|---|---|
| 1 | pi_code |
PI code of the customer the contract applies to. |
| 2 | zindex_nummer |
Z-Index number (8 digits). |
| 3 | ingangs_datum |
Start date, format YYYY-MM-DD. |
| 4 | eind_datum |
End date, format YYYY-MM-DD. |
| 5 | soort |
vast (fixed) or percentage. |
| 6 | vaste_prijs |
For vast: the fixed price per pack (excl. VAT). Empty for percentage. |
| 7 | percentage |
For percentage: discount percentage relative to AIP (0–100). Empty for vast. |
| 8 | distributie |
groothandel (wholesale) or direct. |
| 9 | herkomst |
Free text, origin of the contract. |
| 10 | opmerking |
Free text (optional). |
| 11 | volume_stuks |
Committed annual volume in units (optional, empty/unknown by default). |
| 12 | toeslag |
Surcharge amount (optional). |
| 13 | toeslag_omschrijving |
Description of the surcharge (optional). |
For soort=percentage the final price is calculated server-side from the article's
AIP (just like in the "Add contract" upload function). The afslag type is not
supported when importing contracts.
Examples¶
1. Minimal rows — only the required fields filled in; optional columns
(opmerking, volume_stuks, toeslag, toeslag_omschrijving) remain empty but
the separators stay in place.
671234;12345678;2026-01-01;2026-12-31;vast;100.01;;direct;Inkooptraject 2026;;;;
671234;34567890;2026-01-01;2026-12-31;vast;14.31;;direct;Inkooptraject 2026;;;;
2. Fixed price and discount percentage mixed — for percentage you leave
vaste_prijs empty and fill in percentage; the price is calculated from the AIP.
671234;12345678;2026-01-01;2026-12-31;vast;100.01;;groothandel;Inkooptraject 2026;;1000;;
671234;34567890;2026-01-01;2026-12-31;percentage;;12.5;direct;Inkooptraject 2026;kortingsafspraak;500;;
3. Multiple customers in one upload — each row determines via pi_code which
customer the contract applies to.
671234;12345678;2026-01-01;2026-12-31;vast;100.01;;groothandel;Inkooptraject 2026;;1000;;
671299;12345678;2026-01-01;2026-12-31;vast;98.75;;groothandel;Inkooptraject 2026;;750;;
680055;12345678;2026-01-01;2026-12-31;percentage;;10;direct;Inkooptraject 2026;;250;;
4. With surcharge — a surcharge amount with description and a specified annual volume.
671234;56789012;2026-01-01;2026-12-31;vast;53.23;;groothandel;Inkooptraject 2026;incl. koeltransport;2000;3.50;Koelvergoeding
A comma (,) is also allowed as a separator instead of ;.
Authentication¶
This API uses (identical to the other PharmaPortal APIs): IP whitelisting for
security, an API key for authentication & rate limiting, and HMAC for integrity
checking (mandatory for POST). The API key determines on behalf of which
PharmaPortal organisation the contracts are written. You specify the customer per
row via the pi_code column.
| 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. |
content-type |
text/csv |
Request¶
curl -X POST https://demo.pharma-portal.nl/api/contracten/upload \
-H "x-portal-key: <your-api-key>" \
-H "x-portal-hmac: <sha-512-hmac>" \
-H "content-type: text/csv" \
--data-binary @contracten.csv
Response¶
| Code | Meaning |
|---|---|
200 |
For a processed request (also 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": 2,
"numRowsImported": 2,
"numRowsError": 0,
"errors": []
}
}
Example of a response with row errors:
{
"result": "success",
"data": {
"numRowsTotal": 2,
"numRowsImported": 1,
"numRowsError": 1,
"errors": [
{ "line": 2, "message": "Percentage moet tussen 0 en 100 liggen" }
]
}
}
Example of a response for a request error:
Fields¶
| Field | Type | Description |
|---|---|---|
result |
string | success or error. |
data.numRowsTotal |
integer | Number of rows supplied. |
data.numRowsImported |
integer | Number of contracts created successfully. |
data.numRowsError |
integer | Number of rows with an error (not created). |
data.errors |
object[] | Row errors, with line and message. |
errorMessage |
string | Only for result: error: description of the request error. |
Notes
The HMAC must be computed over the exact CSV bytes of the request body.
Each contract is written with your organisation as owner; leverancier_nummer
remains empty (this is only filled from a completed purchasing round). Each row
is added as a separate contract. The specified volume_stuks is recorded as
the annual volume for the contract.
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. We will then prepare test data for you and provide you with an API key.