Implementing the Cargo Controller Import API

In this article, we provide guidance on how the API of Cargo Controller Import 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. Don’t 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) uses 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 shipping line. If multiple containers are manifested under the B/L, we automatically share these in our updates for all known containers.

Cargo tracking scenarios

There are 3 start moments for tracking cargo within CC that will result in updates being sent to the webhook. The date on which a tracking request is created determines 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.

  1. A track request via a software package. The image below shows an elaboration of the happy flow.

    Track request via CC API in a happy flow, data is available.
  2. A web user manually tracks cargo in the CC web screen. In this situation, a unique trackid is sent to the webhook for which no track request has been sent. This scenario must be followed up:

    Track_scenario_2.png

  3. A commercial release is linked by third parties to your organisation.
    This is virtually the same as scenario 2. An external party links your organisation to the Secure Chain for a container whose B/L you are not yet tracking yourself.
    Secure Chain generates an unexpected CCI webhook update.
  4. 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 supplying this data, it can be checked whether the vessel data is available earlier than the import manifest.
    Track cargo in CC with a CRN or IMO number, then webhook updates will follow even without a 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 is possible that the cargo information is not yet known within Portbase. At that moment, we register your request and automatically provide an update.

  1. Tracked BL: Cargo has been tracked and cargo information is available within the PCS. Schematically, this looks like this:

    Tracked BL status in CC API means that the manifest is available within PCS.

  2. Not tracked BL: Cargo has been tracked and (as yet) no cargo information is available within the PCS. Schematically, this looks like this:

    Not Tracked BL status in CC API means that the manifest is not (yet) available within PCS.

  3. Deleted BL: The cargo was subsequently removed from the manifest. Schematically, it looks like this:

    Deleted BL status in CCI API means that the manifest has been updated and the cargo has been removed from the manifest.

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.

When Cargo Controller Import shares an update, it is delivered to the webhook(s) registered under your organisation in the PCS. If Portbase does not receive a response within 30 seconds, we 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 important update(s) about your cargo.

I can’t translate or rewrite this as a Zendesk article because your input is **not article text**—it’s a **Lucidchart embedded object/diagram JSON** inside a ``. If your goal is to translate the *visible labels in the diagram*, tell me: 1) the **target language** (your rules mention German/English, but you didn’t specify which), and 2) either paste the **diagram text labels only** or upload/export the diagram as **PNG/SVG/PDF** (or provide the original Dutch article content if this belongs to an article). From what’s visible in this JSON, the diagram contains labels like: - “2 Time out (Unhappy flow, detailed on event level)” - “Client” - “Cargo Controller” - “Webhook Events (current status) Contains current cargo and status info” - “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)” - “130 seconds”, “30 seconds” - “//Start Receive update … end //” Send the target language + preferred output format (e.g., a list of `original → translation`, or a fully rewritten caption/legend), and I’ll translate those strings accordingly.I can’t translate or meaningfully rewrite this as a Zendesk article because what you pasted isn’t article content—it’s a Lucidchart embed payload (JSON inside a ``), describing diagram objects (blocks/lines, coordinates, styles, and a few text labels). If you tell me the **target language** (German or English) and what you want changed, I can help in one of these ways: 1. **Translate the diagram labels** inside the payload (e.g. - “Time out (Unhappy flow, detailed on event level)” - “Webhook Events (current status, 2nd try) Contains current cargo and status info” - “Mailnotification (failed update) Contains info about the failed delivery of update” - “Response (200 OK)” - “Client”, “Cargo Controller”, “30 seconds”, “130 seconds”, etc.) and return the same snippet with only those `Text":{"t":"..."}` strings updated. 2. **Extract all visible labels** from the JSON into a clean list (source → translation), so you can update Lucidchart separately. Reply with: - Target language: **German** or **English** - Preferred output: **(A) updated JSON snippet** or **(B) label list** - Any glossary terms I must enforce (if you have them), or confirm “no glossary”.

Time-out errors: Tracking updates from the Cargo Controller Import API are retried up to 3 times.

Implementation advice prevents time-out error messages

Experience shows that many organisations, after the first update, first activate their full internal processing flow. Only after this process has been completed do they send a response to Portbase confirming receipt of the webhook update.

Tracking update from Cargo Controller Import API is answered immediately upon receipt on the first attempt.

Adjust email address for API error messages?

Changes to 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 using 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 apply.

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.

Voyage information (Vessel ETA/ETD)

Follow the expected ETA and ETD of vessels as early as possible by tracking all your cargo using 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 Inspection Portal service, 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 created, it is followed by a release (status released).

If no notification has been registered by Dutch Customs, no notification will be sent at all.

Receive commercial release

Above in the article, in the section Tracking cargo, in scenario 3 we explain tracking cargo that is started by the Secure Chain.

Want to know more about the Secure Chain? Watch the introduction video.

There are 2 ways to be connected to the Secure Chain:

  1. The shipping line releases the cargo to your organisation. 
    1. 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.
    2. You now also have the role of Cargo Controller. Cargo Controllers are shown per container; for each container this can be a different party.
  2. A chain partner releases the cargo to your organisation. 
    1. 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 previously sent values (blank value).

This value will have to be reviewed per container. At that point, contact must be made with the withdrawing party: the shipping line or the chain partner.

Implementation advice: release deadline review 

Commercial releases are often shared with a validity period. Perform a review in your own system to ensure that all planned actions 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: Check every day at 08:00 which commercial releases have expired.

Passing on commercial releases 

After receiving the commercial release, there are 2 possible choices:

  1. Your organisation designates an inland operator (nominate Inland Operator)
  2. Your organisation designates a (different) forwarder (assign 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 Inland Operator role 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 achieve 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 provide all required (mandatory) information yourself to populate the nomination call.

Read here the API specifications to nominate via a PUT request.

Implementation - passing on the role cargo director

A cargo director is assigned based on a unique iAM Connected ID number or a Chamber of Commerce (KvK) number. Your organisation must collect and manage that register itself for all your chain partners.

The iAM Connected ID numbers of your chain partners can be requested via our Sales department. Please also state 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 achieve by performing the action again with the other iAM Connected ID number or Chamber of Commerce (KvK) number.

Withdraw commercial release

If the commercial release needs to be withdrawn, you can use 2 working methods for this:

  1. Withdraw Cargo Director: 
    1. Repeat the action but enter a blank value for the iAM Connected ID number or Chamber of Commerce (KvK) number.
    2. Repeat the action (assign or nominate) but enter the iAM Connected ID number or Chamber of Commerce (KvK) number of your own organisation.
  2. Withdraw Inland Operator: 
    1. Repeat the action but enter a blank value for the EAN number.
    2. Repeat the action but enter a new value directly 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 provide all required (mandatory) information yourself to populate the nomination call.

Implementation advice: Release not passed on after x hours

Commercial releases that are not passed on unnecessarily delay the collection process. Perform a review of whether the commercial release has already been nominated or authorised within the chain.

Validate whether a cargo director or an Inland Operator is already linked to your cargo.

Scenario: Your organisation received the role cargo director on 31-01-2026 23:59. Which cargo has not yet been passed on to an Inland Operator at 01-02-2026 08.00?

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 that it fully reads all available data. 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 will not be released. Submitting an import document is described as an NID notification.

Import Documentation status

The NID notification is fed 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 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 manifest or gate out. Create a trigger in your own system that submits the NID notification at the moment CC receives the discharge confirmation of 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: warn 6 hours after ATA container

Ensure you have 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 Cargo Controller Import web screen. For this, read the article Set up email notifications in Cargo Controller Import You can also integrate this warning into your own systems.

Handling diverted vessels

When vessels are diverted, the discharge terminal is updated so that the vessel call (and manifest) are updated by the shipping agent. If the POD changes because the vessel diverts at the 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 already have been sent.

Create a warning that checks whether the POD changes after you have tracked it. 

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 at the new POD terminal. 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 an nomination has been made, a status request is requested from the terminal. This status reviews 4 values:

  1. Container present?
  2. Customs status?
  3. Import Documentation status?
  4. Terminal status?

These 4 values are updated regularly when the inland operator updates the planning or the commercial release is adjusted. 

The added value of Cargo Controller Import API is that it fully reads all available data. 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 with every update what the status is of the 4 review points. If a review point does not yet have the correct status, the terminal returns this specifically with a 'reject reason'. It can be valuable to monitor these values and provide warnings within your own systems. Read here how this is shown within the web screens; this will provide context for the webhook updates.

Multiple reject reasons can be shared per review point. These are all shown 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, 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. The time is also shared within the container status 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"
},

 

Part of

Was this article helpful?

2 out of 3 found this helpful
Link copied to clipboard