NAV Navbar
shell
  • Introduction
  • Authentication
  • Terminal
  • Maintenance
  • PortCall
  • Port
  • Vessel
  • Subscription
  • Errors
  • What we're working on
  • Introduction

    The Portchain API has been designed following REST principles. Each API is resource oriented and HTTP return codes are used to describe requests status.

    # Curl defaults POST requests to URL encoded data. For example:
    curl "https://api.portchain.com" \
      -X POST \
      # the following line is not necessary
      -H "Content-Type: application/x-www-form-urlencoded" \
      -d "param1":"arg1","param2":"arg2"
    
    # However curl needs your input for JSON formatted payloads
    curl "https://api.portchain.com" \
      -X POST \
      -H "Content-Type: application/json" \
      -d '{"param1":"arg1","param2":"arg2"}'
    

    Resources

    The API is organized around primary resources:

    Typically, an API that allows fetching a list of data will not return the data in depth. To do this, you will need to fetch each item of the list separately.

    Authentication

    # With shell, you can just pass the correct header with each request
    curl "https://api.portchain.com/v1/account" \
      -H "Authorization: YOUR_API_KEY"
    
    # For easier debugging and exploring of the application, you can pass the authorization key in the URL
    curl "https://api.portchain.com/v1/account?Authorization=YOUR_API_KEY"
    

    Portchain uses API keys to allow access to the API. You can request a new API key by emailing your Portchain contact. This API key should be kept confidential and secure.

    Portchain expects for the API key to be included in all API requests to the server in a header that looks like the following:

    Authorization: YOUR_API_KEY

    Access controls

    Portchain uses access controls to restrict the information accessed by third parties. The API key is restricted to only access some specific resources like any other Portchain user.

    Rate limiting

    Headers returned by each API that is rate limited:

    X-RateLimit-limit-per-minute: 100 # your API call alowance per rolling 60 seconds
    X-RateLimit-remaining: 1 # number of remaining API call allowances
    X-RateLimit-next-new-remaining: 30 # time in seconds to wait until you receive at least one new remaining API call allowance
    

    Access to the APIs is rate limited per account. If the rate limit is reached, the HTTP response code is 429.

    Response headers will give you more information about the exact rate limits for each API. The rate limit between APIs may differ as some of them may not be required to be called as often as others.

    Monitoring & logging

    The use of the Portchain API is subject to our Terms of Service and our Privacy Policy.

    In particular, we actively monitor the usage of the API and the source IP addresses.

    We do log all unauthorized accesses and there are mechanisms in place to temporarily block actors that are deemed suspicious. If an API key is banned, the HTTP error code returned will be 403 with an appropriate error message.

    Likewise, IP addresses may be banned should they attempt to use a wrong API key too many times.

    Terminal

    The terminal is a core entity of the BOE.

    List terminals

    To list terminals, you can fetch a specific port

    Fetch a Terminal details

    curl "https://api.portchain.com/v1/terminals/BEANR/BEANR-869" \
      -H "Authorization: YOUR_API_KEY"
    

    The above command returns a JSON object structured like this:

    {
      "key": "BEANR-869",
      "unLocode": "BEANR",
      "name": "PSA Antwerp Europa 869",
      "cranes": [
        {
          "key": "1",
          "label": "C1",
          "rangeFrom": 0,
          "rangeTo": 450,
          "reach": 20
        },...  
      ],
      "maxGangs": 8,
      "minGangs": 2,
      "noLateRampups": true,
      "craneWorkingDistance": 30,
      "minDistBetweenVessels": 50,
      "minTimeBetweenVessels": 90,
      "displayedDistances": "metric"
    }
    

    This endpoint retrieves a specific terminal.

    HTTP request

    GET https://api.portchain.com/v1/terminals/<unLocode>/<terminalKey>

    Parameters

    Parameter Example Description
    unLocode "BEANR" The 5 letters UN/LOCODE of the port
    terminalKey "BEANR-869" The terminal unique key

    Crane

    Each terminal has a number of ship to shore cranes.

    Example of a STS Crane

    {
      "key": "1",
      "label": "C1",
      "rangeFrom": 0,
      "rangeTo": 400,
      "outreach": 61,
      "height": 43
    }
    

    Crane fields

    A Crane resource contains the following fields:

    Update/delete a Terminal

    It is not yet possible to either update nor delete a terminal through the API. Contact us so that we can help with your use case.

    Maintenance

    A Maintenance represents a time window during which:

    The BOE uses maintenances to plan the allocation of cranes and generate alerts and warnings.

    Maintenance fields

    A Maintenance resource contains the following fields:

    List Maintenances

    curl "https://api.portchain.com/v1/maintenances?terminalKey=BEANR-869&from=2017-05-01T00:00:00Z&to=2017-05-31T23:59:59Z" \
      -H "Authorization: YOUR_API_KEY"
    

    The above command returns a JSON array structured like this:

    [
      {
        "id": 1234,
        "type": "quay",
        "startDate": "2017-05-02T08:00:00Z",
        "endDate": "2017-05-03T17:00:00Z",
        "startQuay": 310,
        "endQuay": 330,
        "blockingCranes": false,
        "title": "Repairing damaged fenders",
        "description": "Fenders have been damaged and are scheduled for repair during that period."
      },
      {
        "id": 2345,
        "type": "crane",
        "crane": {
          "key": "1"
        },
        "startDate": "2017-05-15T11:00:00Z",
        "endDate": "2017-05-15T16:00:00Z",
        "startQuay": 560,
        "endQuay": 590,
        "title": "Annual maintenance",
        "description": "This is the annual maintenance of the crane. Must happen no later than May 31st"
      }
    ]
    

    HTTP request

    GET https://api.portchain.com/v1/maintenances?terminalKey=<terminalKey>&from=<from>&to=<to>

    Parameters

    Parameter Example Description
    terminalKey "BEANR-869" The terminal key
    from "2017-05-01T00:00:00Z" The minimum date from which maintenances should be retrieved
    to "2017-05-31T23:59:59Z" The maximum date to which maintenances should be retrieved

    Note that any Maintenance that overlaps with the time window parameters from and to will be included in the results.

    Update a Maintenance

    curl "https://api.portchain.com/v1/maintenances/1234" \
      -X PUT \
      -H "Authorization: YOUR_API_KEY" \
      -d "endDate=2017-05-15T20:00:00Z"
    

    The above command expects a JSON object structured like this:

    {
      "endDate": "2017-05-15T20:00:00Z"
    }
    

    and returns a JSON array structured like this:

    [
      {
        "id": 123,
        "maintenanceId": 1234,
        "field": "endDate",
        "endDate": "2017-05-15T20:00:00Z",
        "author": {
          "type": "system",
          "name": "System 123"
        },
        "createdDate": "2017-05-14T15:23:57Z"
      }
    ]
    

    This endpoint updates a single maintenance. As a confirmation of the change, the generated list of LogEntries are returned by the API.

    You can modify as many fields as you wish in a single API call. Portchain will compare your values against the existing data. Unchanged fields will be ignored and updated fields will be recorded.

    HTTP request

    PUT https://api.portchain.com/v1/maintenances/<maintenanceId>

    Parameters

    Parameter Example Description
    maintenanceId 1234 The unique identifier for that Maintenance

    Create a Maintenance

    curl "https://api.portchain.com/v1/maintenances" \
      -X POST \
      -H "Authorization: YOUR_API_KEY" \
      -d "type=quay" \
      -d "startDate=2017-05-02T08:00:00Z" \
      -d "endDate=2017-05-03T17:00:00Z" \
      -d "startQuay=50"\
      -d "endQuay=550"\
      -d "blockingCranes=true"
      -d "title=Repairing damaged fenders"
    

    The above command returns a JSON object structured like this:

    {
      "id": 1234,
      "type": "quay",
      "startDate": "2017-05-02T08:00:00Z",
      "endDate": "2017-05-03T17:00:00Z",
      "startQuay": 310,
      "endQuay": 330,
      "blockingCranes": false,
      "title": "Repairing damaged fenders",
      "description": "Fenders have been damaged and are scheduled for repair during that period."
    }
    

    This endpoint creates a new Maintenance and returns the created object.

    HTTP request

    POST https://api.portchain.com/v1/maintenances

    JSON parameters

    You can use any Maintenance fields.

    PortCall

    A PortCall (aka. Port of Call) represents a single stop of a container vessel in a container terminal. A PortCall links a vessel Vessel to both a location Terminal+Port and a berthing time (arrival & departure).

    PortCall fields

    A PortCall resource contains the following fields:

    List PortCalls

    curl "https://api.portchain.com/v1/portcalls?terminalKey=BEANR-869&from=2017-01-01T00:00:00Z&to=2017-01-31T23:59:59Z" \
      -H "Authorization: YOUR_API_KEY"
    

    The above command returns a JSON array structured like this:

    [
      {
        "id": "1",
        "key": "ABC1",
        "port": {
          "unLocode": "BEANR",
          "name": "Antwerpen",
          "timeZone": "Europe/Brussels"
        },
        "terminal": {
          "key": "BEANR-869",
          "unLocode": "BEANR",
          "name": "PSA Antwerp Europa 869",
        },
        "vessel": {
          "name": "vessel1",
          "imo": "9275646"
        },
        "arrival": "2017-12-31T23:59:00Z",
        "departure": "2018-01-01T12:00:00Z",
        "..." : "...all other fields hidden for brevity..."
      },
      {
        "id": "2",
        "key": "ABC2",
        "port": {
          "unLocode": "BEANR",
          "name": "Antwerpen",
          "timeZone": "Europe/Brussels"
        },
        "vessel": {
          "key": "N3R",
          "name": "vessel2",
          "imo": "9275647"
        },
        "arrival": "2017-01-01T12:00:00Z",
        "departure": "2018-01-02T12:00:00Z",
        "..." : "...all other fields hidden for brevity..."
      }
    ]
    

    This endpoint retrieves all the port calls that your user has access to, for a specific port/terminal and within a specific time window. Note that the maximum time window is 31 days. The results are ordered by:

    HTTP request

    GET https://api.portchain.com/v1/portcalls?terminalKey=BEANR-869&from=<from>&to=<to>

    Parameters

    Parameter Example Description
    terminalKey
    opt.
    Ignore this field if you're accessing the BOE. Your key has access to a single terminal and you will get an error if you use this field.
    "BEANR-869" The terminal unique key
    from "2017-12-31T23:00:00Z" The minimum date from which port calls should be retrieved (based on Arrival/Departure)
    to "2018-01-01T23:00:00Z" The maximum date to which port calls should be retrieved (based on Arrival/Departure)

    Note that any PortCall that overlaps with the time window parameters from and to will be included in the results.

    Start & End time overlaping PortCalls

    Update a PortCall

    curl "https://api.portchain.com/v1/portcalls/1" \
      -X PUT \
      -H "Authorization: YOUR_API_KEY" \
      -d "arrival=2017-12-31T23:00:00Z" \
      -d "isActual=true"
    

    The above command expects a JSON object structured like this:

    {
      "arrival": "2017-12-31T23:00:00Z",
      "isActual": true
    }
    

    and returns a JSON array structured like this:

    [
      {
        "id": "123",
        "portCall": {
          "id": "1"
        },
        "field": "arrival",
        "arrival": "2017-12-31T23:00:00Z",
        "author": {
          "type": "system",
          "name": "System 123"
        },
        "createdDate": "2017-01-02T12:34:52Z"
      },
      {
        "id": "124",
        "portCall": {
          "id": "1"
        },
        "field": "isActual",
        "isActual": true,
        "author": {
          "type": "system",
          "name": "System 123"
        },
        "createdDate": "2017-01-02T12:34:52Z"
      }
    ]
    

    It is also possible to use a key instead of the id. In that case, omit the port call id from the URL and add the key to the payload:

    curl "https://api.portchain.com/v1/portcalls" \
      -X PUT \
      -H "Authorization: YOUR_API_KEY" \
      -d "key=ABC123" \
      -d "arrival=2017-12-31T23:00:00Z" \
      -d "isActual=true"
    

    The above command expects a JSON object structured like this:

    {
      "key": "ABC123",
      "arrival": "2017-12-31T23:00:00Z",
      "isActual": true
    }
    

    This endpoint updates a single port call. You can modify as many fields as you wish in a single API call. Portchain will compare your values against the existing data. Unchanged fields will be ignored and updated fields will be recorded.

    Note that this API supports Batch actions.

    HTTP request

    PUT https://api.portchain.com/v1/portcalls/<portCallId>

    Parameters

    Parameter Example Description
    portCallId
    ?
    Alternatively you can use the port call key in the body. See Key vs id
    "1234" The unique identifier for that Port Call

    Create a PortCall

    curl "https://api.portchain.com/v1/portcalls" \
      -X POST \
      -H "Authorization: YOUR_API_KEY" \
      -d "arrival=2017-01-01T00:00:00Z" \
      -d "departure=2017-01-02T00:00:00Z" \
      -d "terminalKey=BEANR-869" \
      -d "vesselIMO=9275646"
    

    The above command returns a JSON object structured like this:

    {
      "id": "1",
      "terminal": {
        "key": "BEANR-869",
        "name": "PSA Antwerp Europa 869",
        "port": {
          "unLocode": "BEANR",
          "name": "Antwerpen",
          "timeZone": "Europe/Brussels"
        }
      }
      "vessel": {
        "key": "N2R",
        "name": "BOX EMMA",
        "imo": "9275646"
      },
      "arrival": "2017-12-31T22:00:00Z",
      "departure": "2018-01-01T12:00:00Z"
    }
    

    This endpoint creates a new PortCall and returns the created object.

    Note that this API supports Batch actions.

    HTTP request

    POST https://api.portchain.com/v1/portcalls

    JSON parameters

    You can use any PortCall fields but the following fields are mandatory:

    Parameter Example Description
    unLocode "BEANR" The port of call (cf. Port)
    arrival "2018-12-31T23:59:00Z" The arrival time at berth
    departure "2018-12-31T23:59:00Z" The departure time from berth
    vesselId 1234 The unique Portchain identifier of the vessel

    Delete a PortCall

    PortCalls are never fully deleted. This is because they are usually carrying important audit information. For example, you may want to retroactively analyze if and when carriers skip your terminal.

    curl "https://api.portchain.com/v1/portcalls/1" \
      -X DELETE \
      -H "Authorization: YOUR_API_KEY"
    

    Deleting a port call is the equivalent of setting the portCall.isDeleted boolean field to true.

    Fetch a PortCall

    curl "https://api.portchain.com/v1/portcalls/1" \
      -H "Authorization: YOUR_API_KEY"
    

    The above command returns a JSON object structured like this:

    {
      "id": "1",
      "port": {
        "unLocode": "BEANR",
        "name": "Antwerpen",
        "timeZone": "Europe/Brussels"
      },
      "vessel": {
        "id": 684126,
        "key": "N2R",
        "name": "BOX EMMA",
        "imo": "9275646"
      },
      "arrival": "2017-12-31T23:59:00Z",
      "departure": "2018-01-01T12:00:00Z",
      "craneAllocations": [...],
      ...all other fields hidden for brevity...
    }
    

    This endpoint retrieves a single port call.

    HTTP request

    GET https://api.portchain.com/v1/portcalls/<portCallId>

    Parameters

    Parameter Example Description
    portCallId "1234" The unique identifier for that Port Call

    LogEntry

    Example of a LogEntry

    {
      "id": "1",
      "portCall": {
        "id": "1234"
      },
      "field": "arrival",
      "arrival": "2017-01-01T00:00:00Z",
      "author": {
        "type": "user",
        "fullName": "John Doe"
      },
      "createdDate": "2017-01-02T12:34:52Z"
    }
    

    A PortCall resource receives multiple updates during its lifetime. A LogEntry is a record of a PortCall update.

    LogEntry fields

    A LogEntry resource contains the following fields:

    Crane allocations

    Example of a crane allocations.
    Note that the crane is a shallow object. cf. Terminal Crane.

    {
      "id": "123",
      "craneAllocations": [
        {
          "crane": {
            "key": "1"
          },
          "shifts": [{
            "start": "2017-01-02T04:00:00Z",
            "end": "2017-01-02T08:00:00Z"
          }]
        }
        ...
      ]
    }
    

    The following example demonstrates how one would allocate a single crane to port call with id="123":

    curl -X PUT "https://api.portchain.com/v1/portcalls/123" \
      -H "Authorization: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      --data '{"id": "123", "craneAllocations": [{"crane": {"key": "1"}, "shifts": [{"start":"2017-01-02T04:00:00Z", "end": "2017-01-02T08:00:00Z"}]}]}'
    

    The BOE allocates cranes to port calls. Cranes are allocated to a vessel by time segments. An array of CraneAllocation objects is available on the portcall.craneAllocations field.

    CraneAllocation fields

    A CraneAllocation resource contains the following fields:

    Live moves

    Portchain provides the ability for a third party system (e.g. a TOS) to share live operational data.

    curl "https://api.portchain.com/v1/portcalls" \
      -X PUT \
      -H "Authorization: YOUR_API_KEY" \
      -d "key=NE2X906E" \
      -d "craneName=M2" \
      -d "movesAchieved=217" \
      -d "moveCount=1875"
    

    The above command expects a JSON object structured like this:

    {
      "key": "NE2X906E",
      "crane": {
        "key": "M2",
      },
      "movesAchieved": 217,
      "moveCount": 1895,
    }
    

    You can choose to send more fine grain information by breaking down the types of moves:

    {
      "key": "NE2X906E",
      "crane": {
        "key": "M2",
      },
    
      "loadAchieved": 51,
      "dischargeAchieved": 165,
      "restowAchieved": 0,
    
      "loadCount": 1364,
      "dischargeCount": 511,
      "restowCount": 20
    }
    

    You can also send a batch of data by wrapping all your objects into an array:

    [
      {
        "key": "NE2X906E",
        "crane": {
          "key": "M1"
        },
        ...
      },
      {
        "key": "NE2X906E",
        "crane": {
          "key": "M2"
        },
        ...
      },
      {
        "key": "BE1KJ90W",
        "crane": {
          "key": "C1"
        },
        ...
      },
      ...
    ]
    

    It is possible to share real time crane moves from a third party system into the BOE. This is done through the update port calls API.

    Note that it is possible to either update detailed moves on the port call (e.g. load, discharge and restows) or update the total moves. It is recommended to choose a single of these methods and avoid updating both types of fields (total and detailed). This is because in this case the behaviour of these fields is undertermined.

    Coarse information only stipulates the total number of moves:

    Parameter Example Description
    portCall {"key": "NE2X906E"} An object carrying a key or id to uniquely identify that port call.
    craneName
    opt.
    Optional field. If omitted the moves apply to the whole port call.
    M2 Portchain's crane name.
    ?
    The available cranes can be fetched through the terminal details API.
    moveCount 1895 The total number of moves to achieve.
    movesAchieved 217 The number of moves achieved so far.

    Finer grain information details each type of moves (load, discharge and restow):

    Parameter Example Description
    portCall {"key": "NE2X906E"} An object carrying a key or id to uniquely identify that port call.
    craneName
    opt.
    Optional field. If omitted the moves apply to the whole port call.
    M2 Portchain's crane name.
    ?
    The available cranes can be fetched through the terminal details API.
    loadCount 1364 The number of boxes to load during this port call.
    dischargeCount 511 The number of boxes to discharge during this port call.
    restowCount 20 The number of restows to achieve during this port call.
    loadAchieved 51 The number of boxes that have been loaded so far.
    dischargeAchieved 165 The number of boxes that have been discharged so far.
    restowAchieved 0 The number of restows achieved so far.

    Batch actions

    The following documentation will describe how to create and update port calls. In some cases you may want to create or update multiple port calls at the same time. The API supports this by allowing you to send a JSON array as payload instead of a single port call. When using the batch API, ignore the <portCallId> parameter in the URL and pass either the id or the key into the port call objects in the JSON payload.

    Only the CREATE and UPDATE APIs support batch actions.

    For example, to update port calls with keys ABC1 and ABC2

    curl -X PUT https://api.portchain.com/v1/portcalls ...
    

    JSON payload:

    [
      {
        "key": "ABC1",
        "arrival": "2019-01-01T10:00:00Z",
        "departure": "2018-01-01T18:00:00Z"
      },
      {
        "key": "ABC2",
        "arrival": "2019-01-03T10:00:00Z",
        "departure": "2018-01-03T18:00:00Z"
      }
    ]
    

    Key vs id

    For example, instead of doing the following CREATE and UPDATE API calls

    # CREATE
    curl "https://api.portchain.com/v1/portcalls" \
      -X POST \
      -d "arrival=2017-01-01T00:00:00Z" \
      -d "departure=2017-01-02T00:00:00Z" \
      -d "unLocode=BEANR" \
      -d "vesselIMO=9275646"
    
    # UPDATE
    curl "https://api.portchain.com/v1/portcalls/1" \
      -X PUT \
      -d "arrival=2017-12-31T23:00:00Z"
    

    You would be calling either APIs with a key argument:

    # CREATE
    curl "https://api.portchain.com/v1/portcalls" \
      -X POST \
      -d "key=ABCD123" \
      -d "arrival=2017-01-01T00:00:00Z" \
      -d "departure=2017-01-02T00:00:00Z" \
      -d "unLocode=BEANR" \
      -d "vesselIMO=9275646"
    
    # UPDATE
    curl "https://api.portchain.com/v1/portcalls" \
      -X PUT \
      -d "key=ABCD123" \
      -d "arrival=2017-12-31T23:00:00Z"
    

    Portchain uses auto generated IDs to uniquely identify each port call (field: portCall.id). It is not possible for a third party to control how these IDs are set. However, your system may need to synchronize its own port calls with Portchain.

    To facilitate this, you have the ability to set a key on each port call. When a key is set, it is possible to completely ignore the id and only rely on the key to update port calls and receive port call updates through the subscription API.

    Note that once set, a key can never be changed. You will need to delete the existing port call and re-create a new one with the proper key.

    Port

    The definition of a port sometimes varies from actor to actor. Portchain has decided to base Ports as much as possible on the UN/LOCODE database.

    List ports and their terminals

    curl "https://api.portchain.com/v1/ports/BE" \
      -H "Authorization: YOUR_API_KEY"
    

    The above command returns a JSON array structured like this:

    [
      {
        "unLocode": "BEANR",
        "name": "Antwerpen",
        "timeZone": "Europe/Brussels",
        "latitude": 51.2667,
        "longitude": 4.4167,
        "terminals": [{
          "key": "BEANR-913",
          "name": "PSA Antwerp Noordzee 913"
        }, {
          "key": "BEANR-869",
          "name": "PSA Antwerp Europa 869"
        }, {
          "key": "BEANR-DPW",
          "name": "DP World Antwerp"
        }, {
          "key": "BEANR-CHU",
          "name": "PSA Antwerp Churchill"
        }, ...]
      },
      {
        "unLocode": "BEZEE",
        "name": "Zeebrugge",
        "timeZone": "Europe/Brussels",
        "latitude": 5.333,
        "longitude": 3.2,
        "terminals": [{
          "key": "BEZEE-CHZ",
          "name": "Container Handling Zeebrugge (CHZ)"
        }, {
          "key": "BEZEE-APM",
          "name": "APM Terminals Zeebrugge"
        }, ...]
      }
    ]
    

    It is possible to list ports by country. The available country codes are defined here.

    HTTP request

    GET https://api.portchain.com/v1/ports/<countryCode>

    Query parameters

    Parameter Example Description
    countryCode BE The code of the country for which you want the list of ports

    Fetch a specific Port

    curl "https://api.portchain.com/v1/ports/BEANR" \
      -H "Authorization: YOUR_API_KEY"
    

    The above command returns a JSON object structured like this:

    {
      "unLocode": "BEANR",
      "name": "Antwerpen",
      "timeZone": "Europe/Brussels",
      "latitude": 51.2667,
      "longitude": 4.4167,
        "terminals": [{
          "key": "BEANR-913",
          "name": "PSA Antwerp Noordzee 913"
        }, {
          "key": "BEANR-869",
          "name": "PSA Antwerp Europa 869"
        }, {
          "key": "BEANR-DPW",
          "name": "DP World Antwerp"
        }, {
          "key": "BEANR-CHU",
          "name": "PSA Antwerp Churchill"
        }, ...]
    }
    

    This endpoint retrieves a specific port.

    HTTP request

    GET https://api.portchain.com/v1/ports/<unLocode>

    Parameters

    Parameter Example Description
    unLocode "BEANR" The 5 letters UN/LOCODE of the port

    Vessel

    A vessel represents a ship. A vessel is uniquely identified by its name and its IMO.

    Search for a vessel

    curl "https://api.portchain.com/v1/vessels?searchTerm=Emma" \
      -H "Authorization: YOUR_API_KEY"
    

    The above command returns a JSON array structured like this:

    [
      {
        "name": "EMMA A",
        "imo": 9308194,
        "length": 213,
        "beam": 32,
        "teu": 2760
      },
      {
        "name": "BOX EMMA",
        "imo": 9275646,
        "length": 213,
        "beam": 32,
        "teu": 5048
      },
      {
        "name": "EMMA MAERSK",
        "imo": 9321483,
        "length": 398,
        "beam": 56,
        "teu": 15500
      }
    ]
    

    It is possible to search for vessels. The maximum number of results is 20. The search term is matched against both the vessel name and the vessel IMO number and the results are sorted by best string match.

    HTTP request

    GET https://api.portchain.com/v1/vessels?searchTerm=<searchTerm>

    Query parameters

    Parameter Example Description
    searchTerm "Emma" The search term. It will be matched against both the vessel name and the vessel IMO

    Fetch a specific Vessel

    curl "https://api.portchain.com/v1/vessels/9275646" \
      -H "Authorization: YOUR_API_KEY"
    

    The above command returns a JSON object structured like this:

    {
      "name": "BOX EMMA",
      "imo": 9275646,
      "length": 213,
      "beam": 32,
      "teu": 5048
    }
    

    This endpoint retrieves a specific vessel.

    HTTP Request

    GET https://api.portchain.com/v1/vessels/<vesselIMO>

    URL Parameters

    Parameter Example Description
    vesselIMO 9275646 The IMO number of that vessel

    Subscription

    Portchain relies heavily on the realtime nature of events related to PortCalls. Whether there is a vessel delay, a new question from the terminal or the liner, all these updates are managed by Portchain in real time.

    Subscriptions are a way for your application to receive these events on endpoints. These endpoints must expect HTTP calls with a JSON payload.

    List subscriptions

    curl "https://api.portchain.com/v1/subscriptions" \
      -H "Authorization: YOUR_API_KEY"
    

    The above command returns a JSON array structured like this:

    [
      {
        "name": "My Example Subscription",
        "isActive": true,
        "resource": "terminal",
        "terminal": {
          "unLocode": "BEANR",
          "name": "PSA Antwerp Europa 869"
        },
        "endPoint": {
          "url": "https://endpoint.example.com",
          "authentication": {
            "type": "http-basic",
            "secret": "*abc:*abc"
          }
        },
        "retry": {
          "policy": "exponential-backoff",
          "factor": 2,
          "floor": 60000,
          "ceiling": 21600000
        },
        "batch": {
          "schedule": "0 0 * * *"
        }
      }
    ]
    

    This endpoint retrieves all the subscriptions in your account.

    The response fields are as follow:

    When portchain attempts to connect to your API and sends data, it expects a HTTP 200 status code as a response. If your server returns anything else, Portchain will attempt to retry the request later.

    Portchain will wait more and more time between each new failing attempt to contact your API.

    HTTP request

    GET https://api.portchain.com/v1/subscriptions

    Create a subscription

    curl "https://api.portchain.com/v1/subscriptions" \
      -X POST \
      -H "Authorization: YOUR_API_KEY" \
      -d "name=My Example Subscription" \
      -d "endPoint[url]=https://example.com/abc" \
      -d 'endPoint[headers][...]="...custom headers..."' \
      -d 'type="events"' \
      -d 'watch="PortCall.arrival"' \
      -d 'watch="PortCall.departure"'
    

    An example JSON response is as follow:

    {
      "id": 123,
      "name": "My Example Subscription",
      "isActive": true,
      "resource": "terminal",
      "terminal": {
        "unLocode": "BEANR",
        "name": "PSA Antwerp Europa 869"
      },
      "endPoint": {
        "url": "https://endpoint.example.com",
        "headers": {
          "...": "...custom headers..."
        }
      },
      "retry": {
        "policy": "exponential-backoff",
        "factor": 2,
        "initialBackoff": 1,
        "maximumBackoff": 1440
      },
      "watch": [
        "PortCall"
      ]
    }
    

    A subscription defines:

    You can register up to 5 subscriptions. Each subscription:

    HTTP request

    POST https://api.portchain.com/v1/subscriptions

    Parameters

    Parameter Example Description
    name "My Example Subscription" The name of your subscription.
    endpoint.url "https://api.terminal.com:5443/abc" The endpoint receiving Portchain payloads
    endpoint.headers {"Authorization": "Basic 0..9A..F"} An object representing custom headers
    watch [{"resource":"PortCall", fields:["arrival", "departure", "loadCount", "dischargeCount", "restowCount"]}] An object representing what data to watch
    type events What kind of data should be in the payload.
    batch
    opt.
    Optional field. If missing, data changes are sent in near real time.
    {"schedule": "0 0 * * *"} Whether data should be sent in batches instead of near real time.

    Event types

    We currently only support receiving PortCall updates. You can check the Port call fields to see what fields you can listen on. Note that if you emit the fields attribute from the watched resources, all fields will be watched. Note that a few fields cannot be subscribed to. These are id, key and vessel.

    Update a subscription

    The update of a subscription is similar to creating one:

    curl "https://api.portchain.com/v1/subscriptions/1" \
      -X PUT \
      -H "Authorization: YOUR_API_KEY" \
      -d "isActive=false"
    

    HTTP request

    PUT https://api.portchain.com/v1/subscriptions/<subscriptionId>

    Parameters

    Parameter Example Description
    subscriptionId 1234 The unique identifier of that subscription
    name "My Example Subscription" The name of your subscription.
    endpoint.url "https://api.terminal.com:5443/abc" The endpoint receiving Portchain payloads
    endpoint.headers {"Authorization": "Basic 0..9A..F"} A JSON object representing custom headers
    isActive false Whether you want to temporarily pause the subscription (false) or resume it (true)
    batch
    opt.
    Optional field. If missing, data changes are sent in near real time.
    {"schedule": "0 0 * * *"} Whether data should be sent in batches instead of near real time.

    Delete a subscription

    curl "https://api.portchain.com/v1/subscriptions/1" \
      -X DELETE \
      -H "Authorization: YOUR_API_KEY"
    

    This API irreversibly deletes a subscription from Portchain.

    HTTP request

    DELETE https://api.portchain.com/v1/subscriptions/<subscriptionId>

    Fetch a subscription

    curl "https://api.portchain.com/v1/subscriptions/1" \
      -H "Authorization: YOUR_API_KEY"
    

    The response would be as follow:

    {
      "id": 123,
      "name": "My Example Subscription",
      "isActive": true,
      "resource": "terminal",
      "terminal": {
        "unLocode": "BEANR",
        "name": "PSA Antwerp Europa 869"
      },
      "endPoint": {
        "url": "https://endpoint.example.com",
        "headers": {
          "Authorization": "****"
        }
      },
      "retry": {
        "policy": "exponential-backoff",
        "factor": 2,
        "initial": 1000,
        "ceiling": 1440000
      }
    }
    

    HTTP request

    GET https://api.portchain.com/v1/subscriptions/<id>

    Parameters

    Parameter Description
    id The unique identifier of that subscription

    Payloads

    An example of the payload of a type=objects subscription is as follow:

    {
      "generated": "2017-01-01T00:00:00Z",
      "retryCount": 0,
      "dataType": "PortCall",
      "payloadType": "objects",
      "items": [
        {
          "id": "1",
          "key": "ABC1",
          "port": {
            "unLocode": "BEANR",
            "name": "Antwerpen",
            "timeZone": "Europe/Brussels"
          },
          "terminal": {
            "key": "BEANR-869",
            "unLocode": "BEANR",
            "name": "PSA Antwerp Europa 869",
          },
          "vessel": {
            "name": "vessel1",
            "imo": "9275646"
          },
          "arrival": "2017-12-31T23:59:00Z",
          "departure": "2018-01-01T12:00:00Z",
          "..." : "...all other fields hidden for brevity..."
        },
        {
          "id": "2",
          "key": "ABC2",
          "port": {
            "unLocode": "BEANR",
            "name": "Antwerpen",
            "timeZone": "Europe/Brussels"
          },
          "vessel": {
            "key": "N3R",
            "name": "vessel2",
            "imo": "9275647"
          },
          "arrival": "2017-01-01T12:00:00Z",
          "departure": "2018-01-02T12:00:00Z",
          "..." : "...all other fields hidden for brevity..."
        }
      ]
    }
    

    An example of the payload of a type=events subscription is as follow:

    {
      "generated": "2017-01-01T00:00:00Z",
      "retryCount": 0,
      "dataType": "PortCall",
      "payloadType": "events",
      "items": [
        {
          "id": "1111",
          "key": "ABCD123",
          "field": "departure",
          "departure": "2017-01-02T01:00:00Z",
          "author": {
            "type": "user",
            "fullName": "John Doe"
          },
          "createdDate": "2017-01-02T12:34:52Z"
        },
        {
          "id": "2222",
          "key": "ABCD124",
          "field": "comment",
          "comment": "Hi Mark, is the pilot still ok following the delay on arrival?",
          "author": {
            "type": "user",
            "fullName": "John Doe"
          },
          "createdDate": "2017-01-02T12:34:32Z"
        },
        {
          "id": "3333",
          "key": "ABCD125",
          "field": "arrival",
          "arrival": "2017-01-01T04:00:00Z",
          "author": {
            "type": "user",
            "fullName": "John Doe"
          },
          "createdDate": "2017-01-02T12:34:12Z"
        }
      ]
    }
    

    Portchain sends a POST request to each subscription endpoint with the headers as you configured them.

    When you define your subscription, Portchain will send you a payload whenever relevant data has changed on our servers.

    We operate on a few key principles:

    Payload format

    Each payload is a JSON object. That object contains metadata, like for example the date at which it was generated (generatedDate).

    Fields

    Field Description
    generatedDate the date at which the payloadwas generated
    dataType indicates what resource is being delivered
    type indicates the type of data that is being delivered. objects or events.
    retryCount How many times have this payload been unsuccessfully delivered
    &lt;dataType&gt; the field, in plural that contains an array of all datatypes object created

    The dataType is the top level field that indicates what kind of data is being delivered.

    dataType: 'PortCall'

    When dataType is 'PortCall' two related fields are present in the payload:

    dataType: 'Maintenance'

    When dataType is 'Maintenance' two related fields are present in the payload:

    Errors

    The Portchain API uses the following HTTP error codes:

    Error Code Meaning
    400 Bad Request -- Your request is invalid. There should be more information in the payload.
    401 Unauthorized -- Your API key is absent or incorrect.
    403 Forbidden -- The data requested requires more access rights that you do not have.
    404 Not Found -- The specified data could not be found. There might be more information in the payload.
    405 Method Not Allowed -- You tried to access an API with an invalid method.
    406 Not Acceptable -- You requested a format that isn't json.
    410 Gone -- The data requested has been removed or marked for deletion.
    429 Too Many Requests -- Check the response headers for limit information.
    500 Internal Server Error -- We had a problem with our server. Try again later.
    503 Service Unavailable -- We had a problem with our server. Try again later.

    What we're working on

    If you have feature requests, please email your Portchain representative.

    Events

    We're currently using the events mechanism internally and this part is not yet plugged-into the external API.

    2FA

    Some key actions, like changing the API Key yourself or editing your own subscriptions and endpoints will be subject to 2FA authentication.

    This is to better secure the critical data that Portchain holds.