In this article, we provide advice on how the Cargo Controller Import API can be implemented for your own system. This is explained step by step using use cases. Each use case provides insight into the logistical impact of sharing data via Cargo Controller Import. Do not miss out on any added value by implementing all data points in your own system.
This article is relevant for the project team delivering the implementation.
Tracking cargo
Cargo Controller Import (CCI) works with a RESTful API and Webhook (HTTPS calls). You can find the specifications here.
In the webhook updates, we send the latest known status (state) of your cargo; the full B/L is shared. It is up to the recipient to compare the updates with our previous update to see which data has changed.
To successfully track cargo, a track request must contain at least 2 values: the master B/L number and at least 1 container number.
The master B/L number must include the SCAC code of the carrier. If multiple containers have been manifested under the B/L, we automatically share these in our updates for all known containers.
Cargo tracking scenarios
There are 3 starting points for tracking cargo within CC that trigger updates to be sent to the webhook. The date on which a tracking request is created is the month in which the paid transaction is invoiced.
The developer specifications are available on a separate website. In these blocks, we refer to specific specifications related to a topic.
- A track request via a software package. In the image below an elaboration of the happy flow
-
A web user tracks cargo manually in the CC web screen. In this situation, a unique trackid is sent to the webhook for which no track request was sent. This scenario must be followed up:
- A commercial release is linked by third parties to your organisation.
This is almost identical to scenario 2. An external party links your organisation to the Secure Chain for a container for which you are not yet tracking the B/L yourself. - Add the IMO number or CRN to your track request.
For terminals that provide Premium Terminal Data, it can be useful to receive vessel data as early as possible. By providing this data, we can check whether the vessel data is available earlier than the import manifest.
Why am I not receiving cargo information yet?
The scenarios below assume an Extended tracking situation. If you would like to know more about this, read this release note.
If cargo is being tracked, it may be that the cargo information is not yet known within Portbase. At that point, we register your request and automatically provide an update.
-
Tracked BL: Cargo is tracked and cargo information is available within PCS. Schematically, it looks like this:
-
Not tracked BL: Cargo is tracked and no cargo information is (yet) available within PCS. Schematically, it looks like this:
-
Deleted BL: The cargo was subsequently removed from the manifest. Schematically, it looks like this:
Why do I receive a timeout email on behalf of Cargo Controller Import API?
When tracking a B/L via CC, you receive a unique TrackId in the confirmation that links your organisation to this specific B/L. This way you can easily link all our updates together in your own system.
If Cargo Controller Import shares an update, it is offered to the webhook(s) registered under your organisation in the PCS. If Portbase does not receive a response within 30 seconds, we will make a second attempt and, if necessary, a third attempt.
If, after the third attempt, there is still no response to our update, we send a timeout error message to the email address registered for the webhook (entered when requesting the service): the webhook is not available and you may be missing an important update(s) about your cargo.
The snippet you posted is a **Lucidchart embed payload** (a `` with `data-lucid-content` containing JSON). It defines a diagram (looks like a UML/sequence-style flow) with blocks (e.g., **Client**, **Cargo Controller**) and connecting lines with labels like: - `Webhook Events (current status)` - `Webhook Events (current status, 2nd try)` - `Webhook Events (current status, 3d try)` - `Mailnotification (failed update) Contains info about the failed delivery of update` - `Response (200 OK)` - time markers like `30 seconds`, `130 seconds` What would you like me to do with it? Common options (tell me which one you want): 1) **Extract all visible text** from the diagram (labels in the JSON) into a clean list. 2) **Convert the diagram into a readable description** (step-by-step flow). 3) **Help you embed it properly** in HTML/Zendesk (and troubleshoot why it might not render). 4) **Translate the visible labels** into a specific language (tell me which). Also tell me your target environment (plain HTML page, Zendesk Guide, Confluence, etc.).
Implementation advice prevents time-out error messages
Experience shows that many organisations, after the first update, first activate their complete internal processing workflow. Only after this workflow has been completed do they send a response to Portbase confirming they receive the webhook update.
Adjusting the email address for API error messages?
The change of the email address can be requested via our Integration Services department.
Processing Premium Terminal Data via the API
To receive Premium Terminal Data, some terminals set additional requirements. For this additional data, always track with a CRN or IMO number of the vessel.
How do I receive Premium Terminal Data?
Read here everything about which terminals offer this and the additional conditions they attach to it.
If the conditions are met, all new B/Ls are automatically enriched with additional data. B/Ls from before that time are not updated.
Premium Terminal Data is part of our webhook updates. Read here more about our track requests.
Vessel voyage information (Vessel ETA/ETD)
Track the expected ETA and ETD of vessels as early as possible by tracking all your cargo with an IMO or CRN number.
The terminal ETA and ETD are shared in the object: billOfLading/visitDeclaration/portVisit/berthVisits
Example:
"vesselVisit": {
"crn": "NLRTM21123456",
"portOfCall": {},
"vessel": {},
"visitDeclaration": {
"portVisit": {
"berthVisits": [
{
"berth": {},
"eta": "string",
"ata": "string",
"etd": "string",
"atd": "string",
"etaTerminal": "string",
"etdTerminal": "string"
}
],
"etaPort": "2021-02-28T05:45:00Z",
"etdPort": "2021-02-30T07:30:00Z",
"ataPort": "2021-02-28T05:45:00Z",
"atdPort": "2021-02-30T07:30:00Z"
}
},
"cancelled": false,
"visitStatus": "DEPARTED"
},Expected discharge time (Container EDT)
To receive an expected discharge time, it is necessary for an inland operator to be nominated. By your organisation or someone in the Secure Chain. Read here more about nominating via API.
The EDT is shared per container in the object: billOfLading/hinterlandTerminalData/expectedDischargeTime
Example:
"hinterlandTerminalData": [
{
"equipmentNumber": "CONT9434134",
"expectedDischargeTime": "2021-02-28T07:45:00Z",
"gateOut": "2021-02-28T07:45:00Z"
}
],Tracking customs inspections with the Cargo Controller Import API
Within the service Inspection Portal, notifications of inspections by Dutch Customs and covenant parties (ILT, NVWA, etc.) are passed on. The type of notification is shared in Cargo Controller Import per container in the object: billOfLading/inspectionItems
Example:
"inspectionItems": [
{
"equipmentNumber": "CONT9434134",
"inspectionType": "PHYSICAL_OUTLET",
"status": "NOTIFIED",
"dateUpdated": "2021-02-26T07:45:00Z"
}
],If a notification has been made, it is followed up with a release (status released).
If no notification has been registered by Dutch Customs, no message will follow.
Receiving a commercial release
Above in the article, under the heading Tracking cargo, in scenario 3 we discuss tracking cargo that is initiated by the Secure Chain.
Want to know more about the Secure Chain? Watch the introductory video.
There are 2 ways to be connected to the Secure Chain:
- The carrier releases the cargo to your organisation.
- You now have the role of Release-to Party. The role of Release-to Party is unique; all other roles in the Secure Chain can occur multiple times.
- You now also have the role of Cargo Director. Cargo Directors are shown per container; per container this can be a different party.
- A chain partner releases the cargo to your organisation.
- You now have the role of Cargo Director
The Secure Chain is part of our webhook updates. Read here more about our track requests.
Implement Release-to Party
The role of Release-to Party follows a commercial release per container; this is shared per container in the object: billOfLading/commercialReleases.
Example:
"commercialReleases": [
{
"equipmentNumber": "CONT9434134",
"releaseToParty": {
"name": "string",
"scacCode": "string"
},
"releaseValidUntilDateTime": "2021-02-28T07:45:00Z"
}
],
Implement Cargo Director
The role of Cargo Director follows a commercial release per container; this is shared per container in the object: billOfLading/cargoDirectors.
Example:
"cargoDirectors": [
{
"equipmentNumber": "CONT9434134",
"name": "Cargo Director B.V.",
"scacCode": "CD12"
}
],
Withdraw commercial release
If the commercial release is withdrawn, you will receive a webhook update about this. Portbase shares this update by clearing the values sent earlier (blank value).
This value will need to be reviewed per container. At that time, contact must be made with the withdrawing party: the carrier or the chain partner.
Implementation advice: release review deadline
Commercial releases are often shared with a validity period. Carry out a review in your own system to ensure that all actions that are planned will still take place within this period.
- Scenario 1: The commercial release is valid until 31-01-2026 23:59. The inland operator receives a transport order for 01-02-2026 12:00.
- Scenario 2: Review every day at 08:00 which commercial releases have expired.
Passing on commercial releases
After receiving the commercial release, there are 2 possible choices:
- Your organisation designates an inland operator (nominate Inland Operator)
- Your organisation designates a(nother) forwarder (designate Cargo Director)
Implementation - nominate Inland Operator
An inland operator is nominated based on a unique EAN number. Your organisation must collect and manage that register itself for all your inland operators. Read here our CC API specifications for the technical information.
Read here the API specifications to nominate via a PUT request.
The role of Inland Operator can be passed on per container, or for multiple containers. Confirmation follows only via the webhook updates; this is shared per container in the object: billOfLading/nominatedInlandOperators.
Example:
"nominatedInlandOperators": [
{
"equipmentNumber": "CONT9434134",
"inlandOperatorFullName": "Transport B.V."
}
]
Adjusting the Inland Operator role to another inland operator is easy to implement by performing the action again with a different EAN number.
Implementation advice: Nominate without import manifest
Nomination is possible without an import manifest; in that situation you will have to supply all required (mandatory) information yourself in order to populate the nomination call.
Read here the API specifications to nominate via a PUT request.
Implementation - pass on the Cargo Director role
A Cargo Director is assigned based on a unique iAM Connected ID number or a Chamber of Commerce number. Your organisation must collect and manage that register itself for all your chain partners.
The iAM Connected ID number of your chain partners can be requested via our Sales department. Please also mention the reason for the request.
Read here the API specifications to assign a Cargo Director via a PUT request.
The role of Cargo Director can be passed on per container, or for multiple containers. Confirmation follows only via the webhook updates; this is shared per container in the object: billOfLading/cargoDirectors.
Example:
"cargoDirectors": [
{
"equipmentNumber": "CONT9434134",
"name": "Cargo Director B.V.",
"scacCode": "CD12"
}
],
Adjusting the Cargo Director role to another chain partner is easy to implement by performing the action again with the other iAM Connected ID number or Chamber of Commerce number.
Withdraw commercial release
If the commercial release needs to be withdrawn, you can use 2 working methods:
-
Withdraw Cargo Director:
- Repeat the action but enter a blank value for the iAM Connected ID number or Chamber of Commerce number.
- Repeat the action (assign or nominate) but enter the iAM Connected ID number or Chamber of Commerce number of your own organisation.
-
Withdraw Inland Operator:
- Repeat the action but enter a blank value for the EAN number.
- Repeat the action but directly enter a new value for the EAN number of an inland operator.
The outcome of these actions is confirmed by means of a webhook update. Read here more about our track requests.
Implementation advice: Nominate without import manifest
Nomination is possible without an import manifest; in that situation you will have to supply all required (mandatory) information yourself in order to populate the nomination call.
Implementation advice: Release not passed on after x hours
Commercial releases that are not passed on delay the collection process unnecessarily. Carry out a review to see whether the commercial release has already been nominated or authorised within the chain.
Validate whether a Cargo Director or an Inland Operator has already been linked to your cargo.
Scenario: Your organisation received the Cargo Director role on 31-01-2026 23:59. Which cargo on 01-02-2026 08:00 has not yet been passed on to an Inland Operator?
Monitor Notification Import Documentation
Customers link the service Notification Import Documentation (NID) to the statuses they obtain via the service Cargo Controller Import. Read the implementation advice below to link these services optimally.
The added value of Cargo Controller Import API is reading out all available data in full. Read here more about our track requests and the available data fields.
The timely presence of a correct import document for the cargo is 1 of the 4 review points of a terminal. Without an import document, the cargo is not released. Submitting an import document is described as an NID notification.
Import Documentation status
The NID notification is reported back per container in Cargo Controller Import. Confirmation follows via the webhook updates; this is shared per container in the object: billOfLading/transportEquipmentDeclarations.
Please note! 14 days after the arrival of the vessel (ATA Vessel), an NID notification can no longer be linked with CCI.
Example:
"transportEquipmentDeclarations": [
{
"equipmentNumber": "CONT9434134",
"declarations": [
"DIN"
]
}
],
Implementation advice: ATA Container triggers NID notification (EDI)
Within the NID service there is no link with the manifest or gate out. Create a trigger in your own system that submits the NID notification at the moment CC receives the discharge confirmation for the cargo.
The discharge confirmation is shared per container in the object: billOfLading/dischargeReports.
Example:
"dischargeReports": [
{
"equipmentNumber": "CONT9434134",
"actualDischargeDateTime": "2021-02-28T07:45:00Z",
"dischargeTerminal": {
"code": 4810,
"name": "AMALIAH APMT DSQ",
"ownerFullName": "APM Terminals Maasvlakte II B.V.",
"ownerShortName": "APMII"
}
}
],
Implementation advice: Warning 6 hours after ATA Container
Ensure a review mechanism within your own systems. Portbase offers an option via its web screens to send an email alert. If no NID notification has been submitted 6 hours after the discharge confirmation, we will send a warning by email.
You can set up this notification manually as a user in the web screen of Cargo Controller Import. For this, read the article Set up email notifications in Cargo Controller Import You can also integrate this warning into your own systems.
Coping with vessel diversions
When vessels divert, the discharge terminal is updated so that the vessel visit (and manifest) are updated by the agent. If the POD changes because the vessel diverts last minute, it is necessary that this behaviour is handled immediately. In your own systems, things such as the NID notification or transport orders may have already been sent.
Create a warning that checks whether the POD changes after you have tracked this.
The POD is shared in the object: billOfLading/vesselVisit/dischargeTerminal.
Example:
"dischargeTerminal": {
"code": 4810,
"name": "AMALIAH APMT DSQ",
"ownerFullName": "APM Terminals Maasvlakte II B.V.",
"ownerShortName": "APMII"
},
Implementation advice: POD changes after NID notification
If the POD changes because the vessel diverts, it is necessary that the NID notification is submitted to the terminal at the new POD. The existing NID notification at the previous POD must be withdrawn. Want to know more? Read the article Request to withdraw import document in Notification Import Documentation.
Create a warning in your system that checks whether the POD changes while an import document was known. The POD is shared in the object: billOfLading/vesselVisit/dischargeTerminal.
Example:
"dischargeTerminal": {
"code": 4810,
"name": "AMALIAH APMT DSQ",
"ownerFullName": "APM Terminals Maasvlakte II B.V.",
"ownerShortName": "APMII"
},
terminal pickup data
Within the Secure Chain, the pickup status has become available around the inland operator’s pre-notification at the terminal. From the moment nominated, a status request is requested from the terminal. This status reviews 4 values:
- Container present?
- Customs status?
- Import Documentation status?
- terminal status?
These 4 values are regularly updated when the inland operator updates the planning or the commercial release is adjusted.
The added value of Cargo Controller Import API is reading out all available data in full. Read here more about our track requests and the available data fields.
The pickup status is shared per container in the object: billOfLading/hinterlandPreNotifications.
This also shares what the last update moment was and the modality with which the cargo will be collected.
Example:
"hinterlandPreNotifications": [
{
"equipmentNumber": "string",
"dateUpdated": "string",
"status": "DECLARED",
"modality": "road",
"plannedVisit": {
"eta": "2021-02-28T09:45:00Z",
"ata": "2021-02-28T08:45:00Z"
},
"equipmentStatus": {
"acceptStatuses": [],
"rejectReasons": []
}
}
],
Implementation advice: Identify terminal reject reasons
Terminals indicate in each update what the status is of the 4 review points. If a review point does not yet have the correct status, the terminal will return this specifically with a 'reject reason'. It can be valuable to monitor these values and warn within your own systems.
Per review point, multiple reject reasons can be shared. These are all displayed in the web screens and in the webhook updates of CCI.
The reject reason is shared per container in the object: billOfLading/hinterlandPreNotifications/.../equipmentStatus/rejectReasons.
Examples of reject reasons:
- If the container has not yet been discharged, the container will give a reject reason 'Container not present'. No action required.
- If the NID notification has not been submitted, then the reject reason will be: 'Import document missing in Portbase, contact forwarder'. Action required.
Example:
"hinterlandPreNotifications": [
{
"equipmentNumber": "string",
"dateUpdated": "string",
"status": "DECLARED",
"modality": "road",
"plannedVisit": {
"eta": "2021-02-28T09:45:00Z",
"ata": "2021-02-28T08:45:00Z"
},
"equipmentStatus": {
"acceptStatuses": [
{
"type": "AVAILABLE",
"code": "string",
"remark": "string"
}
],
"rejectReasons": [
{
"code": "string",
"terminalDescription": "string",
"parsedReason": "string"
}
]
}
}
],
Implementation advice: terminal time slot
Not all terminals require a time slot or share a gate out. Within the container status, the time is also shared when an inland operator has a time slot at the terminal.
The pickup status is shared per container in the object: billOfLading/hinterlandPreNotifications/plannedVisit.
Example:
"plannedVisit": {
"eta": "2021-02-28T09:45:00Z",
"ata": "2021-02-28T08:45:00Z"
},
Related to