{ "name": "ELO - Transpas enveloppe request to Douane", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "elo/enveloppe/request", "responseMode": "responseNode", "options": {} }, "id": "28e8e483-27cf-4110-be8a-a002263cf9bf", "name": "Webhook - Transpas ELO request1", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [ 1072, 640 ], "webhookId": "e2dc5153-27d6-4c1c-bf24-f90f8f613d32" }, { "parameters": { "jsCode": "const headers = $json.headers ?? {};\nconst body = $json.body ?? $json;\n\n// Zet hier exact dezelfde token als in Transpas @N8nToken\nconst expectedToken = 'D1KYrH24lxP2HZzW8djssqOB';\n\nconst receivedToken =\n headers['x-elo-token'] ??\n headers['X-Elo-Token'] ??\n headers['X-ELO-TOKEN'] ??\n '';\n\nif (!receivedToken || String(receivedToken).trim() !== expectedToken) {\n throw new Error('Invalid or missing x-elo-token');\n}\n\nif (!body.crossingOrderNr) {\n throw new Error('payload.crossingOrderNr ontbreekt');\n}\n\nif (!body.payloadHash) {\n throw new Error('payload.payloadHash ontbreekt; Transpas moet payloadHash meesturen');\n}\n\nif (!body.douaneEnvelopeBody || typeof body.douaneEnvelopeBody !== 'object') {\n throw new Error('payload.douaneEnvelopeBody ontbreekt; Transpas moet de actuele Douane body meesturen');\n}\n\nconst douaneBody = body.douaneEnvelopeBody;\n\nif (!douaneBody.informationsAppairage || typeof douaneBody.informationsAppairage !== 'object') {\n throw new Error('douaneEnvelopeBody.informationsAppairage ontbreekt');\n}\n\nconst info = douaneBody.informationsAppairage;\n\nif (!['IMPORT', 'EXPORT'].includes(info.sensTraversee)) {\n throw new Error(`Ongeldige sensTraversee: ${info.sensTraversee}`);\n}\n\nif (!['VIDE', 'PLEIN'].includes(info.typeCamion)) {\n throw new Error(`Ongeldig typeCamion: ${info.typeCamion}`);\n}\n\n// Volgens CDS:\n// - VIDE mag zonder formaliteiten.\n// - PLEIN moet een actuele lijst identifiantsDeclaration bevatten.\n// n8n/Postgres bepaalt daarna bij modification zelf wat erbij/eraf moet.\nif (info.typeCamion === 'PLEIN') {\n if (\n !Array.isArray(douaneBody.identifiantsDeclaration) ||\n douaneBody.identifiantsDeclaration.length === 0\n ) {\n throw new Error('typeCamion PLEIN maar douaneEnvelopeBody.identifiantsDeclaration ontbreekt of is leeg');\n }\n}\n\nfunction sqlEscape(value) {\n return String(value ?? '').replace(/'/g, \"''\");\n}\n\nconst trace = {\n crossingStatusLogNr:\n body.crossingStatusLogNr ??\n body.triggerInfo?.crossingStatusLogNr ??\n null,\n\n crossingOrderNr: body.crossingOrderNr ?? null,\n crossing: body.crossing ?? body.triggerInfo?.crossing ?? null,\n sensTraversee: body.sensTraversee ?? info.sensTraversee ?? null,\n typeCamion: body.typeCamion ?? info.typeCamion ?? null,\n\n tripNr:\n body.trip?.tripNr ??\n body.tripNr ??\n body.triggerInfo?.tripNr ??\n null,\n\n tripId:\n body.trip?.tripId ??\n body.tripId ??\n body.triggerInfo?.tripId ??\n null,\n\n tripSequence:\n body.trip?.tripSequence ??\n body.tripSequence ??\n null,\n\n resourceCombinationNr:\n body.resources?.resourceCombinationNr ??\n body.resourceCombinationNr ??\n body.trip?.resourceCombinationNr ??\n null,\n\n truckResourceNr:\n body.resources?.truckResourceNr ??\n body.truckResourceNr ??\n body.triggerInfo?.truck ??\n null,\n\n truckId:\n body.resources?.truckId ??\n body.truckId ??\n null,\n\n truckDescription:\n body.resources?.truckDescription ??\n body.truckDescription ??\n null,\n\n trailerResourceNr:\n body.resources?.trailerResourceNr ??\n body.trailerResourceNr ??\n body.triggerInfo?.trailer ??\n null,\n\n trailerId:\n body.resources?.trailerId ??\n body.trailerId ??\n null,\n\n trailerDescription:\n body.resources?.trailerDescription ??\n body.trailerDescription ??\n null,\n\n driverResourceNr:\n body.resources?.driverResourceNr ??\n body.driverResourceNr ??\n body.triggerInfo?.driver ??\n null,\n\n driverId:\n body.resources?.driverId ??\n body.driverId ??\n null,\n\n driverDescription:\n body.resources?.driverDescription ??\n body.driverDescription ??\n null,\n};\n\nreturn [\n {\n json: {\n payload: body,\n // Dit is de actuele volledige Transpas-body. Postgres maakt hier eventueel modification-body van.\n transpas_douane_body: douaneBody,\n trace,\n\n payload_sql: sqlEscape(JSON.stringify(body)),\n transpas_douane_body_sql: sqlEscape(JSON.stringify(douaneBody)),\n\n crossingOrderNr: body.crossingOrderNr,\n crossingStatusLogNr: trace.crossingStatusLogNr,\n payloadHash: body.payloadHash,\n requestedMessageCode: body.messageCode || 'ENV_CRE01',\n },\n },\n];" }, "id": "f75aae54-2ef6-4761-b784-959e54736825", "name": "Prepare + validate request1", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1296, 640 ] }, { "parameters": { "operation": "executeQuery", "query": "SELECT * FROM elo_register_request('{{ $json.payload_sql }}'::jsonb);", "options": {} }, "id": "cfaceb41-04f7-4383-a433-f710187b7b3d", "name": "Postgres - Register request1", "type": "n8n-nodes-base.postgres", "typeVersion": 2.6, "position": [ 1520, 640 ], "credentials": { "postgres": { "id": "0mT1Cu2z2TS7JEfo", "name": "elo" } } }, { "parameters": { "conditions": { "boolean": [ { "value1": "={{ $json.should_send }}", "value2": true } ] } }, "id": "8b6ff27d-279d-4a90-84eb-d0f4f8dfc51c", "name": "IF - New/changed request?1", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [ 1744, 640 ] }, { "parameters": { "respondWith": "json", "responseBody": "={{ {\n ok: true,\n requestId: $json.request_id,\n correlationId: $json.correlation_id,\n status: $json.status,\n alreadyExists: true,\n shouldSend: false,\n\n requestAction: $json.request_action,\n endpointPath: $json.endpoint_path,\n messageCode: $json.message_code,\n expectedOkMessageCode: $json.expected_ok_message_code,\n expectedErrorMessageCode: $json.expected_error_message_code,\n\n crossingOrderNr: $json.crossing_order_nr,\n crossingStatusLogNr: $('Prepare + validate request1').item.json.trace.crossingStatusLogNr,\n payloadHash: $json.payload_hash,\n version: $json.version,\n\n declarationsToAdd: $json.declarations_to_add,\n declarationsToRemove: $json.declarations_to_remove,\n eloJeton: $json.elo_jeton,\n numeroDossier: $json.numero_dossier,\n\n tripNr: $('Prepare + validate request1').item.json.trace.tripNr,\n tripId: $('Prepare + validate request1').item.json.trace.tripId,\n truckId: $('Prepare + validate request1').item.json.trace.truckId,\n truckDescription: $('Prepare + validate request1').item.json.trace.truckDescription,\n trailerId: $('Prepare + validate request1').item.json.trace.trailerId,\n trailerDescription: $('Prepare + validate request1').item.json.trace.trailerDescription,\n driverId: $('Prepare + validate request1').item.json.trace.driverId,\n driverDescription: $('Prepare + validate request1').item.json.trace.driverDescription\n} }}", "options": { "responseCode": 200 } }, "id": "18fe6ef4-472b-4723-8bf5-e397c6fee457", "name": "Respond - unchanged1", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [ 1968, 736 ] }, { "parameters": { "method": "POST", "url": "https://connexion-api.douane.gouv.fr/oauth2/token", "sendBody": true, "contentType": "form-urlencoded", "bodyParameters": { "parameters": [ { "name": "grant_type", "value": "password" }, { "name": "client_id", "value": "=gun-api" }, { "name": "username", "value": "=DWTProductie" }, { "name": "password", "value": "=wzbnTN#!1Yp2x#&KQ3NM" }, { "name": "scope", "value": "openid" } ] }, "options": {} }, "id": "92349a19-cbe4-4861-b91a-f38e7bb5db51", "name": "HTTP - Get Douane token1", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1968, 544 ] }, { "parameters": { "method": "POST", "url": "={{ 'https://api.douane.gouv.fr/sibrexit' + $('Postgres - Register request1').item.json.endpoint_path }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "=Bearer {{ $json.access_token }}" }, { "name": "Content-Type", "value": "application/json" }, { "name": "messageCode", "value": "={{ $('Postgres - Register request1').item.json.message_code }}" }, { "name": "messageId", "value": "={{ $('Postgres - Register request1').item.json.message_id }}" }, { "name": "functionalId", "value": "={{ $('Postgres - Register request1').item.json.functional_id }}" }, { "name": "correlationId", "value": "={{ $('Postgres - Register request1').item.json.correlation_id }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ $('Postgres - Register request1').item.json.douane_body }}", "options": { "response": { "response": { "fullResponse": true, "neverError": true, "responseFormat": "text" } } } }, "id": "afcc706b-4060-4c7b-bb4a-38c7ee2f7f2a", "name": "HTTP - Send envelope to Douane1", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 2192, 544 ], "continueOnFail": true }, { "parameters": { "jsCode": "const req = $('Postgres - Register request1').item.json;\nconst prepared = $('Prepare + validate request1').item.json;\nconst send = $json ?? {};\n\nfunction sqlEscape(value) {\n return String(value ?? '').replace(/'/g, \"''\");\n}\n\nlet httpStatus =\n send.statusCode ??\n send.status ??\n send.response?.statusCode ??\n send.error?.statusCode ??\n null;\n\nlet bodyText =\n send.body ??\n send.data ??\n send.responseBody ??\n send.response?.body ??\n '';\n\nlet responseForDb = {\n statusCode: httpStatus,\n statusMessage: send.statusMessage ?? send.statusText ?? null,\n headers: send.headers ?? null,\n body: bodyText,\n raw: send,\n};\n\nlet errorText = null;\n\nif (send.error) {\n errorText =\n typeof send.error === 'string'\n ? send.error\n : JSON.stringify(send.error);\n}\n\nif (httpStatus !== null && (httpStatus < 200 || httpStatus >= 300)) {\n errorText = errorText || `Douane HTTP ${httpStatus}`;\n}\n\n// Als Douane 2xx geeft met lege/text response, is dat geen fout.\n// De echte inhoudelijke uitslag komt later via callback.\nreturn [\n {\n json: {\n request_id: req.request_id,\n http_status: httpStatus ?? 200,\n response_json_sql: sqlEscape(JSON.stringify(responseForDb)),\n response_text_sql: sqlEscape(\n typeof bodyText === 'string' ? bodyText : JSON.stringify(bodyText)\n ),\n error_text_sql: errorText ? sqlEscape(errorText) : null,\n\n requestId: req.request_id,\n correlationId: req.correlation_id,\n crossingOrderNr: req.crossing_order_nr,\n crossingStatusLogNr: prepared.trace.crossingStatusLogNr,\n payloadHash: req.payload_hash,\n version: req.version,\n\n requestAction: req.request_action,\n endpointPath: req.endpoint_path,\n messageCode: req.message_code,\n expectedOkMessageCode: req.expected_ok_message_code,\n expectedErrorMessageCode: req.expected_error_message_code,\n declarationsToAdd: req.declarations_to_add,\n declarationsToRemove: req.declarations_to_remove,\n eloJeton: req.elo_jeton,\n numeroDossier: req.numero_dossier,\n\n trace: prepared.trace,\n },\n },\n];" }, "id": "77ab3db5-0b3d-4387-8fb4-435125ac9390", "name": "Prepare send result1", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2416, 544 ] }, { "parameters": { "operation": "executeQuery", "query": "SELECT * FROM elo_mark_request_send_result(\n {{ $json.request_id }}::bigint,\n {{ $json.http_status }}::int,\n '{{ $json.response_json_sql }}'::jsonb,\n '{{ $json.response_text_sql }}'::text,\n {{ $json.error_text_sql ? \"'\" + $json.error_text_sql + \"'\" : \"NULL\" }}::text\n);", "options": {} }, "id": "c64d5f53-4f8b-4dd3-9a0d-591754b90d9a", "name": "Postgres - Mark send result1", "type": "n8n-nodes-base.postgres", "typeVersion": 2.6, "position": [ 2640, 544 ], "credentials": { "postgres": { "id": "0mT1Cu2z2TS7JEfo", "name": "elo" } } }, { "parameters": { "respondWith": "json", "responseBody": "={{ {\n ok: true,\n requestId: $('Prepare send result1').item.json.requestId,\n correlationId: $('Prepare send result1').item.json.correlationId,\n status: $json.status,\n alreadyExists: false,\n shouldSend: true,\n\n requestAction: $('Prepare send result1').item.json.requestAction,\n endpointPath: $('Prepare send result1').item.json.endpointPath,\n messageCode: $('Prepare send result1').item.json.messageCode,\n expectedOkMessageCode: $('Prepare send result1').item.json.expectedOkMessageCode,\n expectedErrorMessageCode: $('Prepare send result1').item.json.expectedErrorMessageCode,\n\n crossingOrderNr: $('Prepare send result1').item.json.crossingOrderNr,\n crossingStatusLogNr: $('Prepare send result1').item.json.crossingStatusLogNr,\n payloadHash: $('Prepare send result1').item.json.payloadHash,\n version: $('Prepare send result1').item.json.version,\n\n declarationsToAdd: $('Prepare send result1').item.json.declarationsToAdd,\n declarationsToRemove: $('Prepare send result1').item.json.declarationsToRemove,\n eloJeton: $('Prepare send result1').item.json.eloJeton,\n numeroDossier: $('Prepare send result1').item.json.numeroDossier,\n\n tripNr: $('Prepare send result1').item.json.trace.tripNr,\n tripId: $('Prepare send result1').item.json.trace.tripId,\n truckId: $('Prepare send result1').item.json.trace.truckId,\n truckDescription: $('Prepare send result1').item.json.trace.truckDescription,\n trailerId: $('Prepare send result1').item.json.trace.trailerId,\n trailerDescription: $('Prepare send result1').item.json.trace.trailerDescription,\n driverId: $('Prepare send result1').item.json.trace.driverId,\n driverDescription: $('Prepare send result1').item.json.trace.driverDescription\n} }}", "options": { "responseCode": 200 } }, "id": "42c30d31-b5c6-4591-99bd-2600cdc6e52e", "name": "Respond - accepted1", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [ 2864, 544 ] }, { "parameters": { "content": "## ELO Transpas → n8n → Douane v5\nPostgres elo_register_request bepaalt nu automatisch:\n- demandeCreation → ENV_CRE01 → /enveloppe\n- demandeModification → ENV_MOD01 → /enveloppe/modifier\n\nn8n gebruikt altijd de waarden uit Postgres:\n- endpoint_path voor de URL\n- message_code voor de header\n- functional_id voor de header\n- douane_body voor de body\n\nTranspas blijft alleen de actuele volledige stand meesturen.\nPostgres berekent bij modification zelf AAjouter/ASupprimer.", "height": 256, "width": 432 }, "type": "n8n-nodes-base.stickyNote", "typeVersion": 1, "position": [ 1008, 304 ], "id": "69879c7f-e87b-414b-9208-5c207b3895c5", "name": "Sticky Note1" } ], "pinData": { "Webhook - Transpas ELO request1": [ { "json": { "headers": { "connection": "Keep-Alive", "host": "n8n.tmsconnector.nl", "x-forwarded-scheme": "https", "x-forwarded-proto": "https", "x-forwarded-for": "217.67.225.160", "x-real-ip": "217.67.225.160", "content-length": "3208", "content-type": "application/json; charset=utf-8", "accept": "application/json", "user-agent": "Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)", "x-elo-token": "D1KYrH24lxP2HZzW8djssqOB" }, "params": {}, "query": {}, "body": { "payloadVersion": 7, "sourceSystem": "Transpas", "eventType": "ELO_ENVELOPPE_REQUEST", "requestAction": "demandeCreation", "messageCode": "ENV_CRE01", "expectedOkMessageCode": "ENV_CRE02", "expectedErrorMessageCode": "ENV_CRE03", "crossingStatusLogNr": 109822, "crossingOrderNr": 11214, "crossing": 7, "sensTraversee": "EXPORT", "typeCamion": "PLEIN", "company": 1, "crossingProvider": 7, "crossingProviderAccount": 3, "crossingId": 7976558, "crossingDeparture": 72, "crossingClass": 27, "crossingDate": "2026-06-24T00:00:00", "departureDate": "2026-06-24T00:00:00", "ediReference": "99146813", "externalOrderId": "99146813", "lastSentOrderId": "11214-444451", "confirmedOrderId": "11214-444451", "gmr": "GMRA011ISJDI", "borderPassReference": "OC99146813", "transpasVehicleTypeCode": "Truck+Trailer", "identifiantsDeclarationDebug": "[\"26NL000432WGEIC8J7\",\"26NL000432ZXXWH1J6\"]", "ensCount": 0, "declarationCountWithoutEns": 2, "tripNr": "444453", "tripId": "444451", "tripSequence": "3", "resourceCombinationNr": "511731", "truckResourceNr": "127340", "truckId": "9141", "truckDescription": "9141 - BB-135-S", "trailerResourceNr": "127341", "trailerId": "9106-1", "trailerDescription": "9106-1 - OR-70-GX", "driverResourceNr": "118821", "driverDescription": "Van der Zwan", "triggerInfo": { "crossingStatusLogNr": 109822, "crossingOrderNr": 11214, "crossing": 7, "statusKind": 7, "statusDateTime": "2026-06-24T14:23:43.023", "crossingId": 7976558, "crossingProviderAccount": 3, "departureDate": "2026-06-24T00:00:00", "crossingDeparture": 72, "crossingClass": 27, "tripNr": 444453, "tripId": 444451, "truck": 127340, "trailer": 127341, "driver": 118821, "numberOfDrivers": 1, "cumShipments": 2, "length": 17 }, "trip": { "tripNr": 444453, "tripId": 444451, "tripActivityNr": 7976558, "tripSequence": 3, "resourceCombinationNr": 511731, "mainCombinationNr": 511731, "plannedDateTime": "2026-06-24T22:00:00", "departureDateTime": "2026-06-24T22:20:00", "cumShipments": 2, "cumLoadingMeter": 13, "cumVolume": 47.595, "cumPalletPlaces": 26.15, "cumContainers": 43.36, "tripName": "13. Folkestone Webshop" }, "resources": { "resourceCombinationNr": 511731, "truckResourceNr": 127340, "truckId": "9141", "truckDescription": "9141 - BB-135-S", "trailerResourceNr": 127341, "trailerId": "9106-1", "trailerDescription": "9106-1 - OR-70-GX", "driverResourceNr": 118821, "driverDescription": "Van der Zwan" }, "legs": [ { "legNr": 3268335, "transit": 0, "orderLegNr": 3268335, "salesOrderNr": 881645, "salesOrderId": 966963, "salesOrderSequence": 1, "customer": 103201, "debtor": 94743, "customsTransitNr": 20839, "mrn": "26NL000432WGEIC8J7", "declarationDate": "2026-06-24T00:00:00" }, { "legNr": 3268336, "transit": 0, "orderLegNr": 3268336, "salesOrderNr": 881645, "salesOrderId": 966963, "salesOrderSequence": 2, "customer": 103201, "debtor": 94743, "customsTransitNr": 20840, "mrn": "26NL000432ZXXWH1J6", "declarationDate": "2026-06-24T00:00:00" } ], "documents": [], "douaneEnvelopeBody": { "informationsAppairage": { "sensTraversee": "EXPORT", "typeCamion": "PLEIN", "estTIRATA": false, "possedeContratTransport": false, "estPostal": false, "estEmballageVide": false, "estSPS": false, "estProduitPeche": false }, "identifiantsDeclaration": [ "26NL000432WGEIC8J7", "26NL000432ZXXWH1J6" ] }, "payloadHash": "C8272D380C59DA8D235D8186E865AC9BDC25E54E5E1A4752D857E8EF8169C258" }, "webhookUrl": "https://n8n.tmsconnector.nl/webhook/elo/enveloppe/request", "executionMode": "production" }, "pairedItem": { "item": 0 } } ] }, "connections": { "Webhook - Transpas ELO request1": { "main": [ [ { "node": "Prepare + validate request1", "type": "main", "index": 0 } ] ] }, "Prepare + validate request1": { "main": [ [ { "node": "Postgres - Register request1", "type": "main", "index": 0 } ] ] }, "Postgres - Register request1": { "main": [ [ { "node": "IF - New/changed request?1", "type": "main", "index": 0 } ] ] }, "IF - New/changed request?1": { "main": [ [ { "node": "HTTP - Get Douane token1", "type": "main", "index": 0 } ], [ { "node": "Respond - unchanged1", "type": "main", "index": 0 } ] ] }, "HTTP - Get Douane token1": { "main": [ [ { "node": "HTTP - Send envelope to Douane1", "type": "main", "index": 0 } ] ] }, "HTTP - Send envelope to Douane1": { "main": [ [ { "node": "Prepare send result1", "type": "main", "index": 0 } ] ] }, "Prepare send result1": { "main": [ [ { "node": "Postgres - Mark send result1", "type": "main", "index": 0 } ] ] }, "Postgres - Mark send result1": { "main": [ [ { "node": "Respond - accepted1", "type": "main", "index": 0 } ] ] } }, "active": true, "settings": { "executionOrder": "v1", "binaryMode": "separate", "timeSavedMode": "fixed", "errorWorkflow": "1Ps5lukDf2sgcGL7", "callerPolicy": "workflowsFromSameOwner", "availableInMCP": false }, "versionId": "206630fe-70a1-4ef2-8467-6c0a89d883da", "meta": { "templateCredsSetupCompleted": true, "instanceId": "bef8d409866a58c0777dfe7cca1b9c2400fd051c056d361501393ab423006b5f" }, "nodeGroups": [], "id": "n0EGzoG2DGvV4Vo3", "tags": [] }