Editie 2026 · direct bericht in jouw systeem bij elke statuswijziging
Zo werkt de webhook
4
Instellen in het platform
6
Wat je ontvangt: payload en headers
9
Verificatie van het token
13
Koppelen aan de publieke API
17
Checklist en veelgestelde vragen
19
1
Zo werktde webhook
1. Zo werkt de webhook
Webhook handleiding4
Met de boeking webhook stuurt het Import4You platform direct een bericht (een HTTP POST verzoek) naar een adres van jouw keuze, zodra de status of de verwachte leverdatum van een boeking verandert. Je hoeft dus niet zelf te controleren of er nieuws is: het bericht bevat het boekingsnummer, je eigen kenmerk, schip, container, de datums, de producten en de nieuwe status of leverdatum.
1
Status verandert
Bijvoorbeeld van Collection naar Onderweg, of de verwachte leverdatum schuift
2
Wij sturen een POST
Naar elk adres dat je hebt geregistreerd, met de boekingsgegevens als JSON
3
Jij controleert
Met het token in de header en je client_secret bewijs je dat het van ons komt
4
Jij verwerkt
Antwoord met 2xx en werk je eigen systeem bij
2
Instellen inhet platform
2. Instellen in het platform
Webhook handleiding6
Het adres van jouw server waar wij het bericht naartoe sturen, bijvoorbeeld https://api.jouwbedrijf.nl/import4you/webhook. Het moet van buitenaf bereikbaar zijn en een geldig HTTPS certificaat hebben.
Je kunt meer dan één adres registreren. Elk adres ontvangt elk bericht onafhankelijk van de andere adressen.
Deze inloggegevens zijn niet dezelfde als de API sleutels (i4y_test_ of i4y_live_) onder Public API Keys. Gebruik een API secret nooit als webhook sleutel en andersom.
2. Instellen in het platform
Webhook handleiding7
Alles in de 200 reeks betekent voor ons "goed ontvangen". Een andere code of een time-out betekent dat het bericht niet is aangekomen. Gebruik de Testknop in het platform om te controleren of je endpoint goed antwoordt.
Moet je adres beperkt bereikbaar zijn, laat dan verzoeken van het Import4You platform door. Vraag de actuele uitgaande adressen op via support@import4you.nl.
3
Payload enheaders
3. Wat je ontvangt
Webhook handleiding9
Je endpoint ontvangt een POST verzoek met deze JSON. Het veld event.target zegt wat er veranderd is: status of delivery.expected_date.
{ "data": { "entity": "booking", "event": { "name": "updated", "target": "status | delivery.expected_date" }, "data": { "id": 1, "uuid": "string", "vessel_name": "string | null", "container_number": "string | null", "etd_date": "dd.mm.yyyy | null", "eta_date": "dd.mm.yyyy | null", "personal_ref": "string", "products": [ { "ean_code": "string", "product_name": "string", "start_boxes_count": 10, "box_count": 8, "items_per_box": 12, "product_subs": [ { "uuid": "string", "description": "string", "ean_code": "string", "start_boxes_count": 5, "boxes": 4, "items_per_box": 6 } ] } ], "status": { "id": 1, "name": "Collection" }, "expected_delivery_date": "dd.mm.yyyy" } } }
Veld
Betekenis
entity
Altijd booking
event.name
Altijd updated
event.target
status of delivery.expected_date
data.id
Intern nummer, alleen ter informatie
data.uuid
Het publieke boekingsnummer, zoals SI4Y-000123. Dit gebruik je om de boeking terug te vinden
data.personal_ref
Je eigen kenmerk uit de boeking
vessel_name, container_number
Schip en container, leeg als nog niet bekend
etd_date, eta_date
Verwachte vertrek en aankomstdatum, dd.mm.jjjj, leeg als nog niet bekend
products[]
Producten met EAN, naam, dozen bij start en nu, stuks per doos en eventuele subproducten
status
Alleen bij target status: id en naam zoals het platform die toont
expected_delivery_date
Alleen bij target delivery.expected_date: de nieuwe verwachte leverdatum, dd.mm.jjjj
Datums in de webhook zijn dd.mm.jjjj. De publieke API gebruikt ISO datums (jjjj-mm-dd) en UTC tijdstippen. Houd daar rekening mee als je beide combineert.
3. Wat je ontvangt
Webhook handleiding10
{ "data": { "entity": "booking", "event": { "name": "updated", "target": "status" }, "data": { "id": 4471, "uuid": "SI4Y-000123", "vessel_name": "MSC Oscar", "container_number": "MSCU1234567", "etd_date": "12.11.2026", "eta_date": "20.12.2026", "personal_ref": "REF-4471", "products": [ { "ean_code": "1234567890123", "product_name": "Widget", "start_boxes_count": 10, "box_count": 10, "items_per_box": 10, "product_subs": [] } ], "status": { "id": 5, "name": "In transit" } } } }
{ "data": { "entity": "booking", "event": { "name": "updated", "target": "delivery.expected_date" }, "data": { "id": 4471, "uuid": "SI4Y-000123", "vessel_name": "MSC Oscar", "container_number": "MSCU1234567", "etd_date": "12.11.2026", "eta_date": "22.12.2026", "personal_ref": "REF-4471", "products": [ ... ], "expected_delivery_date": "28.12.2026" } } }
Kijk eerst naar event.target. Bij status staat er een status object en geen expected_delivery_date. Bij delivery.expected_date is het andersom. De voorbeeldwaarden hierboven zijn fictief; de statusnamen volgen het platform.
3. Wat je ontvangt
Webhook handleiding11
Elk bericht heeft drie HTTP headers. Met token en je client_secret controleer je dat het bericht echt van Import4You komt en onderweg niet is aangepast.
token: {hmac_signature} client_id: {jouw_client_id} Content-Type: application/json
Header
Betekenis
token
De handtekening: een HMAC SHA256 in hexadecimale vorm (64 tekens), berekend met jouw client_secret. Zie hoofdstuk 4
client_id
Jouw client_id uit Instellingen → Automatisering. Gebruik hem om het juiste secret op te zoeken als je er meerdere hebt
Content-Type
Altijd application/json
Iedereen die je adres kent, zou er iets naartoe kunnen sturen. De handtekening kan alleen gemaakt worden met jouw secret, dat alleen jij en Import4You kennen. Klopt hij niet, dan gooi je het bericht weg.
Vergelijk de client_id header met de waarde uit het platform. Zo weet je zeker dat je met het juiste secret controleert, ook als je ooit nieuwe inloggegevens maakt.
HTTP headernamen zijn niet hoofdlettergevoelig. Sommige frameworks tonen ze als Token of Client-Id. Lees ze dus hoofdletterongevoelig uit.
4
Verificatievan het token
4. Verificatie van het token
Webhook handleiding13
Het token is een HMAC SHA256 over een Base64 versie van de inhoud van het veld data. De volgorde en de exacte bytes zijn belangrijk, dus volg de stappen precies.
token = hex(HMAC_SHA256(secret, base64_zonder_padding(ruwe_data_json)))
Ons platform maakt de JSON met de standaard PHP instellingen: een / wordt \/ en niet ASCII tekens worden \uXXXX. Als jouw taal het object opnieuw zou schrijven, kan dat afwijken. Door de originele tekst te gebruiken, controleer je precies wat wij hebben ondertekend.
De payload heeft twee keer een veld data: het bovenste (de ondertekende inhoud) en daarbinnen de boekingsgegevens. Je knipt alleen het bovenste uit.
4. Verificatie van het token
Webhook handleiding14
const express = require("express"), crypto = require("crypto"); const app = express(); const SECRET = process.env.I4Y_WEBHOOK_SECRET; const CLIENT_ID = process.env.I4Y_WEBHOOK_CLIENT_ID; // Ruwe body bewaren: geen express.json() op deze route app.post("/import4you/webhook", express.raw({ type: "application/json" }), (req, res) => { const raw = req.body.toString("utf8"); const token = req.get("token") || ""; if (req.get("client_id") !== CLIENT_ID) return res.sendStatus(401); // 1. waarde van het bovenste "data" uitknippen const colon = raw.indexOf(":", raw.indexOf('"data"')); const inner = raw.slice(colon + 1, raw.lastIndexOf("}")).trim(); // 2. base64 zonder padding, 3. HMAC SHA256 hex const b64 = Buffer.from(inner, "utf8").toString("base64").replace(/=+$/, ""); const expected = crypto.createHmac("sha256", SECRET).update(b64).digest("hex"); // 4. constant time vergelijken const ok = expected.length === token.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(token)); if (!ok) return res.sendStatus(401); // 5. nu pas parsen en verwerken const payload = JSON.parse(inner); const boeking = payload.data; console.log(boeking.uuid, payload.event.target, boeking.status?.name ?? boeking.expected_delivery_date); res.sendStatus(200); });
Sla het geparste bericht op en geef meteen 200 terug. Verdere verwerking doe je daarna, zodat je endpoint altijd op tijd met 2xx antwoordt.
4. Verificatie van het token
Webhook handleiding15
<?php $secret = getenv("I4Y_WEBHOOK_SECRET"); $raw = file_get_contents("php://input"); $token = $_SERVER["HTTP_TOKEN"] ?? ""; $clientId = $_SERVER["HTTP_CLIENT_ID"] ?? ""; if ($clientId !== getenv("I4Y_WEBHOOK_CLIENT_ID")) { http_response_code(401); exit; } // Bovenste "data" uit de ruwe tekst knippen $start = strpos($raw, '"data"'); $colon = strpos($raw, ":", $start); $end = strrpos($raw, "}"); $inner = trim(substr($raw, $colon + 1, $end - $colon - 1)); $b64 = rtrim(base64_encode($inner), "="); $expected = hash_hmac("sha256", $b64, $secret); if (!hash_equals($expected, $token)) { http_response_code(401); exit; } $payload = json_decode($inner, true); $boeking = $payload["data"]; // ... opslaan en verwerken http_response_code(200);
Ons platform is in PHP gebouwd. Daarom werkt hier ook json_encode(json_decode($raw, true)["data"]) als basis, zolang je geen JSON vlaggen meegeeft. De uitknipmethode is in elke taal veilig.
import base64, hmac, hashlib, json, os from flask import Flask, request, abort app = Flask(__name__) SECRET = os.environ["I4Y_WEBHOOK_SECRET"].encode() CLIENT_ID = os.environ["I4Y_WEBHOOK_CLIENT_ID"] @app.post("/import4you/webhook") def webhook(): raw = request.get_data(as_text=True) token = request.headers.get("token", "") if request.headers.get("client_id") != CLIENT_ID: abort(401) start = raw.index('"data"') colon = raw.index(":", start) end = raw.rindex("}") inner = raw[colon + 1:end].strip() b64 = base64.b64encode(inner.encode("utf-8")) \ .decode().rstrip("=") expected = hmac.new(SECRET, b64.encode(), hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, token): abort(401) payload = json.loads(inner) boeking = payload["data"] # ... opslaan en verwerken return "", 200
Gebruik de Testknop in het platform. Ontvang je 401 in je eigen log, controleer dan of je echt de ruwe body gebruikt en of het secret klopt. Verificatievoorbeelden met testwaarden staan ook in het platform onder Automatisering.
5
Koppelen aande publieke API
5. Koppelen aan de publieke API
Webhook handleiding17
De webhook meldt dat er iets veranderd is. De publieke API (live eind november 2026) geeft de volledige boeking met de vaste statuscodes en alle datums. Zo horen de velden bij elkaar.
1
Webhook komt binnen
Status of leverdatum veranderd voor SI4Y-000123
2
Token controleren
Hoofdstuk 4
3
Boeking ophalen
GET /bookings/SI4Y-000123 met een API token
4
Eigen systeem bijwerken
Met de vaste statuscode en alle datums
In de webhook
In de publieke API
Gebruik
data.data.uuid
Boeking id, bijvoorbeeld SI4Y-000123
Gebruik dit in GET /bookings/{uuid} en GET /bookings/{uuid}/events
data.data.id
Geen
Intern nummer, niet bruikbaar in de API
data.data.personal_ref
personal_ref
Je eigen kenmerk, gelijk in beide
data.data.status.name
status als vaste code
De webhook geeft de naam uit het platform ("Collection"), de API een vaste code (collecting, in_transit). Bouw je logica op de API code
etd_date, eta_date, expected_delivery_date (dd.mm.jjjj)
dates.estimated_departure_date, dates.estimated_arrival_date, dates.planned_delivery_date (jjjj-mm-dd)
Zelfde informatie, ander formaat
products[] met EAN en naam
products[] met UUID's
Productregels in de webhook hebben geen API ID. Zoek producten op via de boeking in de API
Webhook: client_id en client_secret uit Instellingen → Automatisering. Publieke API: een sleutel uit Instellingen → Public API Keys die je inwisselt voor een Bearer token. Ze zijn niet uitwisselbaar.
Dan heb je per bericht het boekingsnummer, je eigen kenmerk, schip, container, de datums, de producten en de statusnaam of de nieuwe verwachte leverdatum.
6
Checklisten vragen
6. Checklist en veelgestelde vragen
Webhook handleiding19
2events
Status en leverdatum
Dit zijn de twee gebeurtenissen die de webhook nu stuurt, allebei met event.name updated.
1of meer
Adressen
Elk geregistreerd HTTPS adres ontvangt elk bericht.
1secret
Eén sleutel om te controleren
Roteer je het secret in het platform, pas dan ook je endpoint aan.
6. Checklist en veelgestelde vragen
Webhook handleiding20
Ja. De boeking webhook staat in het platform onder Instellingen → Automatisering. De publieke API, waarmee je de volledige boeking kunt ophalen, volgt eind november 2026.
Ja, voor elke boeking van je bedrijf, zodra de status of de verwachte leverdatum verandert. Je hoeft niets per boeking in te stellen.
Komt een bericht de eerste keer niet aan (geen 2xx), dan bieden we het opnieuw aan. Blijft je endpoint langer onbereikbaar, haal dan de actuele status op in het platform of via de publieke API.
De webhook stuurt de statusnaam zoals die in het platform heet. Wil je vaste codes om op te programmeren, gebruik dan de publieke API: die geeft altijd dezelfde Engelse code, los van de weergave.
Nee. De webhook stuurt alleen gebeurtenissen van boekingen. Zendingen volg je via de publieke API met GET /shipments/{id}/events.
Bijna altijd één van deze drie: je gebruikt een geparsed object in plaats van de ruwe tekst, je vergeet de = tekens van de Base64 weg te halen, of je neemt de hele body in plaats van alleen de waarde van data.
Mail support@import4you.nl met het boekingsnummer en het tijdstip van het bericht, of gebruik de contactpagina .
Editie 2026 · direct bericht in jouw systeem bij elke statuswijziging
Met de boeking webhook stuurt het Import4You platform direct een bericht (een HTTP POST verzoek) naar een adres van jouw keuze, zodra de status of de verwachte leverdatum van een boeking verandert. Je hoeft dus niet zelf te controleren of er nieuws is: het bericht bevat het boekingsnummer, je eigen kenmerk, schip, container, de datums, de producten en de nieuwe status of leverdatum.
client_id en een client_secret.Het adres van jouw server waar wij het bericht naartoe sturen, bijvoorbeeld https://api.jouwbedrijf.nl/import4you/webhook. Het moet van buitenaf bereikbaar zijn en een geldig HTTPS certificaat hebben.
Je kunt meer dan één adres registreren. Elk adres ontvangt elk bericht onafhankelijk van de andere adressen.
Deze inloggegevens zijn niet dezelfde als de API sleutels (i4y_test_ of i4y_live_) onder Public API Keys. Gebruik een API secret nooit als webhook sleutel en andersom.
Content-Type: application/json accepterentoken controleren voordat je iets verwerktuuid, zonder het secrettarget of extra velden negeren in plaats van er een fout op te geven, dan blijft je koppeling werken bij uitbreidingenAlles in de 200 reeks betekent voor ons "goed ontvangen". Een andere code of een time-out betekent dat het bericht niet is aangekomen. Gebruik de Testknop in het platform om te controleren of je endpoint goed antwoordt.
Moet je adres beperkt bereikbaar zijn, laat dan verzoeken van het Import4You platform door. Vraag de actuele uitgaande adressen op via support@import4you.nl.
Je endpoint ontvangt een POST verzoek met deze JSON. Het veld event.target zegt wat er veranderd is: status of delivery.expected_date.
{
"data": {
"entity": "booking",
"event": {
"name": "updated",
"target": "status | delivery.expected_date"
},
"data": {
"id": 1,
"uuid": "string",
"vessel_name": "string | null",
"container_number": "string | null",
"etd_date": "dd.mm.yyyy | null",
"eta_date": "dd.mm.yyyy | null",
"personal_ref": "string",
"products": [
{
"ean_code": "string",
"product_name": "string",
"start_boxes_count": 10,
"box_count": 8,
"items_per_box": 12,
"product_subs": [
{
"uuid": "string",
"description": "string",
"ean_code": "string",
"start_boxes_count": 5,
"boxes": 4,
"items_per_box": 6
}
]
}
],
"status": { "id": 1, "name": "Collection" },
"expected_delivery_date": "dd.mm.yyyy"
}
}
}
| Veld | Betekenis |
|---|---|
| entity | Altijd booking |
| event.name | Altijd updated |
| event.target | status of delivery.expected_date |
| data.id | Intern nummer, alleen ter informatie |
| data.uuid | Het publieke boekingsnummer, zoals SI4Y-000123. Dit gebruik je om de boeking terug te vinden |
| data.personal_ref | Je eigen kenmerk uit de boeking |
| vessel_name, container_number | Schip en container, leeg als nog niet bekend |
| etd_date, eta_date | Verwachte vertrek en aankomstdatum, dd.mm.jjjj, leeg als nog niet bekend |
| products[] | Producten met EAN, naam, dozen bij start en nu, stuks per doos en eventuele subproducten |
| status | Alleen bij target status: id en naam zoals het platform die toont |
| expected_delivery_date | Alleen bij target delivery.expected_date: de nieuwe verwachte leverdatum, dd.mm.jjjj |
dd.mm.jjjj. De publieke API gebruikt ISO datums (jjjj-mm-dd) en UTC tijdstippen. Houd daar rekening mee als je beide combineert.{
"data": {
"entity": "booking",
"event": { "name": "updated", "target": "status" },
"data": {
"id": 4471,
"uuid": "SI4Y-000123",
"vessel_name": "MSC Oscar",
"container_number": "MSCU1234567",
"etd_date": "12.11.2026",
"eta_date": "20.12.2026",
"personal_ref": "REF-4471",
"products": [
{
"ean_code": "1234567890123",
"product_name": "Widget",
"start_boxes_count": 10,
"box_count": 10,
"items_per_box": 10,
"product_subs": []
}
],
"status": { "id": 5, "name": "In transit" }
}
}
}
{
"data": {
"entity": "booking",
"event": { "name": "updated",
"target": "delivery.expected_date" },
"data": {
"id": 4471,
"uuid": "SI4Y-000123",
"vessel_name": "MSC Oscar",
"container_number": "MSCU1234567",
"etd_date": "12.11.2026",
"eta_date": "22.12.2026",
"personal_ref": "REF-4471",
"products": [ ... ],
"expected_delivery_date": "28.12.2026"
}
}
}
Kijk eerst naar event.target. Bij status staat er een status object en geen expected_delivery_date. Bij delivery.expected_date is het andersom. De voorbeeldwaarden hierboven zijn fictief; de statusnamen volgen het platform.
Elk bericht heeft drie HTTP headers. Met token en je client_secret controleer je dat het bericht echt van Import4You komt en onderweg niet is aangepast.
token: {hmac_signature}
client_id: {jouw_client_id}
Content-Type: application/json
| Header | Betekenis |
|---|---|
token | De handtekening: een HMAC SHA256 in hexadecimale vorm (64 tekens), berekend met jouw client_secret. Zie hoofdstuk 4 |
client_id | Jouw client_id uit Instellingen → Automatisering. Gebruik hem om het juiste secret op te zoeken als je er meerdere hebt |
Content-Type | Altijd application/json |
Iedereen die je adres kent, zou er iets naartoe kunnen sturen. De handtekening kan alleen gemaakt worden met jouw secret, dat alleen jij en Import4You kennen. Klopt hij niet, dan gooi je het bericht weg.
Vergelijk de client_id header met de waarde uit het platform. Zo weet je zeker dat je met het juiste secret controleert, ook als je ooit nieuwe inloggegevens maakt.
HTTP headernamen zijn niet hoofdlettergevoelig. Sommige frameworks tonen ze als Token of Client-Id. Lees ze dus hoofdletterongevoelig uit.
Het token is een HMAC SHA256 over een Base64 versie van de inhoud van het veld data. De volgorde en de exacte bytes zijn belangrijk, dus volg de stappen precies.
data uit die tekst. Dus alles tussen {"data": en de laatste }. Gebruik niet JSON.stringify of json.dumps op een geparsed object: grote getallen en decimalen kunnen dan net anders worden geschreven en dan klopt de handtekening niet meer.= tekens aan het einde weg.client_secret als sleutel. Neem de hexadecimale uitkomst.token header, met een constant time vergelijking. Gelijk? Dan verwerk je het bericht. Daarna parse je de uitgeknipte data tekst als JSON.token = hex(HMAC_SHA256(secret, base64_zonder_padding(ruwe_data_json)))
Ons platform maakt de JSON met de standaard PHP instellingen: een / wordt \/ en niet ASCII tekens worden \uXXXX. Als jouw taal het object opnieuw zou schrijven, kan dat afwijken. Door de originele tekst te gebruiken, controleer je precies wat wij hebben ondertekend.
De payload heeft twee keer een veld data: het bovenste (de ondertekende inhoud) en daarbinnen de boekingsgegevens. Je knipt alleen het bovenste uit.
const express = require("express"), crypto = require("crypto");
const app = express();
const SECRET = process.env.I4Y_WEBHOOK_SECRET;
const CLIENT_ID = process.env.I4Y_WEBHOOK_CLIENT_ID;
// Ruwe body bewaren: geen express.json() op deze route
app.post("/import4you/webhook", express.raw({ type: "application/json" }),
(req, res) => {
const raw = req.body.toString("utf8");
const token = req.get("token") || "";
if (req.get("client_id") !== CLIENT_ID) return res.sendStatus(401);
// 1. waarde van het bovenste "data" uitknippen
const colon = raw.indexOf(":", raw.indexOf('"data"'));
const inner = raw.slice(colon + 1, raw.lastIndexOf("}")).trim();
// 2. base64 zonder padding, 3. HMAC SHA256 hex
const b64 = Buffer.from(inner, "utf8").toString("base64").replace(/=+$/, "");
const expected = crypto.createHmac("sha256", SECRET).update(b64).digest("hex");
// 4. constant time vergelijken
const ok = expected.length === token.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(token));
if (!ok) return res.sendStatus(401);
// 5. nu pas parsen en verwerken
const payload = JSON.parse(inner);
const boeking = payload.data;
console.log(boeking.uuid, payload.event.target,
boeking.status?.name ?? boeking.expected_delivery_date);
res.sendStatus(200);
});
express.raw in plaats van express.json, zodat de originele bytes beschikbaar blijventimingSafeEqual voor de vergelijkingSla het geparste bericht op en geef meteen 200 terug. Verdere verwerking doe je daarna, zodat je endpoint altijd op tijd met 2xx antwoordt.
<?php
$secret = getenv("I4Y_WEBHOOK_SECRET");
$raw = file_get_contents("php://input");
$token = $_SERVER["HTTP_TOKEN"] ?? "";
$clientId = $_SERVER["HTTP_CLIENT_ID"] ?? "";
if ($clientId !== getenv("I4Y_WEBHOOK_CLIENT_ID")) {
http_response_code(401); exit;
}
// Bovenste "data" uit de ruwe tekst knippen
$start = strpos($raw, '"data"');
$colon = strpos($raw, ":", $start);
$end = strrpos($raw, "}");
$inner = trim(substr($raw, $colon + 1, $end - $colon - 1));
$b64 = rtrim(base64_encode($inner), "=");
$expected = hash_hmac("sha256", $b64, $secret);
if (!hash_equals($expected, $token)) {
http_response_code(401); exit;
}
$payload = json_decode($inner, true);
$boeking = $payload["data"];
// ... opslaan en verwerken
http_response_code(200);
Ons platform is in PHP gebouwd. Daarom werkt hier ook json_encode(json_decode($raw, true)["data"]) als basis, zolang je geen JSON vlaggen meegeeft. De uitknipmethode is in elke taal veilig.
import base64, hmac, hashlib, json, os
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["I4Y_WEBHOOK_SECRET"].encode()
CLIENT_ID = os.environ["I4Y_WEBHOOK_CLIENT_ID"]
@app.post("/import4you/webhook")
def webhook():
raw = request.get_data(as_text=True)
token = request.headers.get("token", "")
if request.headers.get("client_id") != CLIENT_ID:
abort(401)
start = raw.index('"data"')
colon = raw.index(":", start)
end = raw.rindex("}")
inner = raw[colon + 1:end].strip()
b64 = base64.b64encode(inner.encode("utf-8")) \
.decode().rstrip("=")
expected = hmac.new(SECRET, b64.encode(),
hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, token):
abort(401)
payload = json.loads(inner)
boeking = payload["data"]
# ... opslaan en verwerken
return "", 200
Gebruik de Testknop in het platform. Ontvang je 401 in je eigen log, controleer dan of je echt de ruwe body gebruikt en of het secret klopt. Verificatievoorbeelden met testwaarden staan ook in het platform onder Automatisering.
De webhook meldt dat er iets veranderd is. De publieke API (live eind november 2026) geeft de volledige boeking met de vaste statuscodes en alle datums. Zo horen de velden bij elkaar.
| In de webhook | In de publieke API | Gebruik |
|---|---|---|
data.data.uuid | Boeking id, bijvoorbeeld SI4Y-000123 | Gebruik dit in GET /bookings/{uuid} en GET /bookings/{uuid}/events |
data.data.id | Geen | Intern nummer, niet bruikbaar in de API |
data.data.personal_ref | personal_ref | Je eigen kenmerk, gelijk in beide |
data.data.status.name | status als vaste code | De webhook geeft de naam uit het platform ("Collection"), de API een vaste code (collecting, in_transit). Bouw je logica op de API code |
etd_date, eta_date, expected_delivery_date (dd.mm.jjjj) | dates.estimated_departure_date, dates.estimated_arrival_date, dates.planned_delivery_date (jjjj-mm-dd) | Zelfde informatie, ander formaat |
products[] met EAN en naam | products[] met UUID's | Productregels in de webhook hebben geen API ID. Zoek producten op via de boeking in de API |
Webhook: client_id en client_secret uit Instellingen → Automatisering. Publieke API: een sleutel uit Instellingen → Public API Keys die je inwisselt voor een Bearer token. Ze zijn niet uitwisselbaar.
Dan heb je per bericht het boekingsnummer, je eigen kenmerk, schip, container, de datums, de producten en de statusnaam of de nieuwe verwachte leverdatum.
event.name updated.Ja. De boeking webhook staat in het platform onder Instellingen → Automatisering. De publieke API, waarmee je de volledige boeking kunt ophalen, volgt eind november 2026.
Ja, voor elke boeking van je bedrijf, zodra de status of de verwachte leverdatum verandert. Je hoeft niets per boeking in te stellen.
Komt een bericht de eerste keer niet aan (geen 2xx), dan bieden we het opnieuw aan. Blijft je endpoint langer onbereikbaar, haal dan de actuele status op in het platform of via de publieke API.
De webhook stuurt de statusnaam zoals die in het platform heet. Wil je vaste codes om op te programmeren, gebruik dan de publieke API: die geeft altijd dezelfde Engelse code, los van de weergave.
Nee. De webhook stuurt alleen gebeurtenissen van boekingen. Zendingen volg je via de publieke API met GET /shipments/{id}/events.
Bijna altijd één van deze drie: je gebruikt een geparsed object in plaats van de ruwe tekst, je vergeet de = tekens van de Base64 weg te halen, of je neemt de hele body in plaats van alleen de waarde van data.
Mail support@import4you.nl met het boekingsnummer en het tijdstip van het bericht, of gebruik de contactpagina.