# Dataloy VMS API

**The&#x20;*****Dataloy VMS API***  documentation is intended as the main source of information and answers to queries and issues regarding integration with Dataloy VMS. It provides an overview of how integration with Dataloy VMS may be accomplished and detailed information about each type of integration.&#x20;

High focus has been placed on quality of standard, substance and user-friendliness. The API knowledge base is kept continuously up-to-date. There is also a questions & answers section and a troubleshooting article section..<br>

To search/navigate either click the links below or use the left-hand navigation panel to search by keyword, category or hierarchy.

*API:*

* [What is it?](/api-release-8.26/dataloy-rest-api/what-is-it)
* [Authentication / Authorization](/api-release-8.26/dataloy-rest-api/authentication-authorization)
* [Getting Started](/api-release-8.26/dataloy-rest-api/getting-started)
* [Data Model](/api-release-8.26/dataloy-rest-api/data-model)
* [Filtering](/api-release-8.26/dataloy-rest-api/filtering)
* [Sorting](/api-release-8.26/dataloy-rest-api/sorting)
* [Pagination](/api-release-8.26/dataloy-rest-api/pagination)
* [Adjust Number of Fields to be Returned from a Request](/api-release-8.26/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request)
* [Webhooks](/api-release-8.26/dataloy-rest-api/webhooks)
* [Master Data Objects](/api-release-8.26/dataloy-rest-api/master-data-objects)

[*User Guides*](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414844/User+Guides)*:*

* [Accounting Integration API](/api-release-8.26/user-guides/accounting-integration-api)
* [Schedule API](/api-release-8.26/user-guides/schedule-api)
* [Bunker Order Integration API](/api-release-8.26/user-guides/bunker-order-integration-api)
* [Service Order Integration API](/api-release-8.26/user-guides/service-order-integration-api)
* [Vessel Report](/api-release-8.26/user-guides/vessel-report)
* [Consumptions API](/api-release-8.26/user-guides/bunker-consumption-api)
* [Market Index API](/api-release-8.26/user-guides/market-index-integration-api)

*Questions & Answers, Troubleshooting Articles:*<br>

* [Questions & Answers API](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414741)
* [Troubleshooting Articles API](https://dataloy-cloud.atlassian.net/wiki/pages/createpage.action?spaceKey=VMSINT\&title=Troubleshooting%20Articles%20API\&linkCreation=true\&fromPageId=923414838)


# What is it?

**The Dataloy REST API** allows for the retrieval, updating and entry of all data in Dataloy VMS.&#x20;

As the Dataloy API is based on REST principles it is easy to write and simple to use when testing applications.

A typical company uses many applications, of which many or most are not designed to work with one another. Integrating separate, but related, applications help organizations achieve greater levels of operational consistency, efficiency and quality. Integration can be considered if a system generates/consumes data relevant to Dataloy VMS and/or can share data with the VMS.&#x20;


# Authentication / Authorization

Authentication and authorization is done through OAuth 2.

To get access to the protected resources OAuth 2.0 uses Access Tokens. An Access Token is a string representing the granted permissions.

To access to Dataloy API, you must request an Access Token.&#x20;

To obtain an access token you  need to do a POST request, to  the provided URL, passing the client id and client secret in the payload

Example of POST payload to token URL

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
"client_id":"G99j845dM4MtckQlKt8E6o......",
"client_secret":"-mMElVOMzvht2SyQPfVh-WIaPCbOxRdWN5YngBxtBKybQmli-....",
"audience":"https://dataloy.internal",
"grant_type":"client_credentials"
}
</code></pre></td></tr></tbody></table>

#### Parameters

| Parameter Name  | Description                                                                                                                                                    |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `grant_type`    | Set this to "client\_credentials".                                                                                                                             |
| `client_id`     | Your M2M Client ID.                                                                                                                                            |
| `client_secret` | Your M2M Client Secret.                                                                                                                                        |
| `audience`      | The audience for the token, which is your API. For production environments use "<https://dataloy>". For  test and DEV environments use "<https://dataloy.dev>" |
|                 |                                                                                                                                                                |

#### Response

If all goes well, you'll receive an HTTP 200 response with a payload containing `access_token`, `token_type`, and `expires_in` values:

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1....................fXClgZe2pFQBxPqARz9xfWlrFnc1El34ZPyRLoGlLIJLiE0NvOA1JLWycXCNo9N7AenAKEbj-gb2eW4TnpAiidDRmMV3m36UCuRAxWdVcvsRaJxXcquf79wAgEoEKriJklCxwKOnOyngbTZ2vDNim0nrw6-W0NOjRARkkY_w-188dY829z_urjsWuCC7TOMwfrQDLL2h72L2UrqlyL0hHMGQesau6h8KUsGg3EIoWPQ-Pf6o2CNCtGyr7DNuuLpCw9HqXiz5v-RIvKLBoaRMAAJJqBeXvpPvOcyicBlalcTWB5NMCe6Ldi9xqFmwjhO1CAtIk9QUa8wsOcXxg",
"expires_in": 86400,
"token_type": "Bearer"
}
</code></pre></td></tr></tbody></table>

#### Call API endpoint

To call an API endpoint you must pass the retrieved Access Token as a Bearer token in the Authorization header of your HTTP request.

\
curl https\://{URL}/ws/rest/{Resource}-H "Authorization: Bearer eyJ.........qLbZQ"

When an endpoint is invoked with an expired token the server sends a HTTP 401 response with the following payload:

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
    "statusCode": 401,
    "statusText": "Unauthorized",
    "message": "Token expired.",
    "date": "2019-11-13T06:26:01",
    "statusFamily": "CLIENT_ERROR",
    "method": "GET",
    "uri": "http://platform-dev.dataloy.com/ws/rest/Cargo?filter=subCargos.freight%28GTE%292500000"
</code></pre></td></tr></tbody></table>

The client should not ask for a new token for each call but use the same token as long as it is valid.


# Getting Started

**Getting Started with Dataloy REST API** (*Application Programming Interface*) provides an introduction to the Dataloy API directed towards developers and IT-personnel. Basics, such as how to obtain, submit and modify data, are explained.

Dataloy’s API uses a REST interface over HTTP/HTTPS. The currently supported payload is application/JSON.

## **To Get Started**

Follow the below steps - they will return USD currency from Dataloy VMS (illustrating that the API works properly):

```
https://[ip]:[port]/ws/rest/Currency?filter=currencyCode(EQ)USD
```

## **Request Format**

For **POST** and **PUT requests,** the payload *must* be **JSON** and the **Content-Type** be set to **application/JSON**.

**Base URL**

The base URL is **customer-specific**. To obtain the IP-address and port for the specific API installation, please **contact** [**Dataloy**](mailto:support@dataloy.com).

```
https://[ip]:[port]/ws/rest
```

\
**IMPORTANT**: All URLs in this documentation is relative to the root URL stated below. The HTTP method will be written in front of the relative URL:\
***Note**: The root URL should NOT be hardcoded in your application to allow it to run against multiple servers. The "/ws/rest" part may also change in the future.*

```
GET /Cargo/123456
```

Example:\
\
*When the documentation refers to /Cargo, the full URL is https\://\[ip]:\[port]/ws/rest/Cargo.*<br>

## **General URL Structure**

Resources *(for example: Voyage, Document, ExchnangeRate)*, have a similar general URL structure.\
\
Example:\
\
*In the table below* "/Entity" *represents the name of an entity type like* "/Cargo" *or* "/Voyage"*.*

| Relative URL | Methods          | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ------------ | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|              | GET, POST        | <ul><li>Represents the collection of entities of the given type.</li><li>GET will return a filterable array of entities of that type.</li><li>These entities will be "minimized" and sometimes contain only the "key" and "self" properties.</li><li>POST will insert a new entity of that type into the collection.</li></ul>                                                                                                                                                                                                                                                                                                               |
|              | GET, PUT, DELETE | <ul><li>Represents a single entity of the given type, identified by "key".</li><li>GET will return the full representation of that entity.</li><li>PUT will update the given entity. A PUT request may contain only the changed properties, and will return the full object after the change. From API version 3, PUT will also update Sub-objects, previous versions are limited to object by object updating. For API versions prior to version 3, Sub-objects should <strong>NOT</strong> be included in PUT requests.</li><li>DELETE will return 200 OK and an empty body when successful. Not all entities can be be deleted.</li></ul> |

## **Exception Handling**

Dataloy's API return HTTP status codes in the HTTP header and provides additional information in the body in **JSON format**.

{% hint style="info" %}
This example has been updated for API version 2.0.0 using date format yyyy-dd-MMThh:mi:ss to conform ISO 8601, versions prior to 2.0.0 has the following date format: yyyy-dd-MM hh:mi:ss
{% endhint %}

```
{
    "statusCode": 400,
    "statusText": "Bad Request",
    "message": "Missing field(s) in json body. All fields are required.",
    "date": "2013-02-05T09:49:52",
    "statusFamily": null,
    "method": null,
    "uri": null
}
```

\
**Retrieve Data from Dataloy API**
----------------------------------

Information is retrieved by using a **GET request on a URL**. Each resource has it’s own URL. The API also supports searching resource specific parameters.

GET request on a URL:

Example: \
\
*The following GET request on example URL will return the document with ID 2729538.*

| `https://server.com/ws/rest/Document/2729538` |
| --------------------------------------------- |

\
**Filtering Data**
------------------

Dataloy API is equipped with a strong generic filtering functionality. It is able to filter on almost any field visible in the API and filtering any resources returning an array of objects (see [Filtering](/api-release-8.26/dataloy-rest-api/filtering)). <br>

## **Modifying Data Through Dataloy API (PUT)**

Use **PUT** to modify data through the API. Specify the **URL of a resource** and send the content to be modified in the **body of the HTTP call**. A successful PUT will return the same body as a GET on that resource. Excluded properties will be **ignored**. Excluded array elements will be **removed**. From API version 3, PUT will also update Sub-objects, previous versions are limited to object by object updating. For API versions prior to version 3, Sub-objects should **NOT** be included in PUT requests.

Examples:&#x20;

\
**Updating** properties for a **main object**. In this case VoyageHeader

```
{
   "doProfitLoss": 1.1,
   "tradeVoyageNo": 2345,
   "isBudget": true,
   "voyageStartDate": "2017-03-01T01:58:00",
   "referenceNo": "12341"
}
```

**Updating** properties for a **sub-object**. In this case, Voyage is the main object and Cargo is the sub-object

```
{
    "cargos": [
        {
            "bookedQuantity": 10000        
        }
    ]
}
```

**Insert** an **array element**

```
{
  "remarks": [
      {
           "remarkTitle": "A Test remark title 1"
      }
   ]
}
```

**Update** an **array element** by including the key for the array element. The key is generated by the API when inserting a new element.

```
{
  "remarks": [
      {
           "key": 234581088,
           "remarkTitle": "A Test remark title 1 Updated"
      }
   ]
}
```

**Insert** a second **array element** by including the key for the first array element. Then add a second array element without a key.

```
{
  "remarks": [
      {
           "key": 234581088,
           "remarkTitle": "A Test remark title 1 Updated"
      },
       {
           "remarkTitle": "A Test remark title 2"
      }
   ]
}
```

**Remove** an **array element**. When having two elements in an array, you can remove one of them by removing the element in the PUT body

```
{
  "remarks": [
      {
           "key": 234581088
      }
   ]
}
```

## **Sub-objects**

Inserting (POST) or updating (PUT) references to sub-objects can be done in different ways:\
*(All the examples below is using VoyageHeader as a main object and the specified company will be linked to the VoyageHeader.)*

*Specify the **key** to an existing sub-object*

All existing objects has a key that is created by Dataloy API. This can be used for linking an existing object to another object.

```
{   "company":4601029}
```

*Specify the **code** to an existing sub-object*

[A lot of the objects in Dataloy API has an unique code that can be used for identifying an object.](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414749/List+of+API+Resources+having+Code+Properties) This code can also be used for linking an existing object to another object.

```
{   "company": "09"}
```

*Specify the **sub-object***

Another option for linking a sub-object is to provide the object to be linked.

```
{   "company": {       "key": 163348582   }}
```

*Create a **new object***

The last option is to create a new sub-object and link it to a object in the same request. When excluding the key property a new object will be created.

```
{
   "company": {       
       "companyCode": "1234",
       "companyName": "Test Company"
   }
}
```

## **Inserting Data Through Dataloy API (POST)**

Send a **POST request** to a base resource URL with a body conforming with the minimum requirements of that resource.

Example: \
\
*POST request URL:*&#x20;

| `https://ip:port/ws/rest/Document` |
| ---------------------------------- |

{% hint style="info" %}
All the dates are in the format **yyyy-dd-MMThh:mi:ss** to conform ISO 8601
{% endhint %}

&#x20;**Body of Document HTTP POST**

```
{
    "documentAmount": 0.0,
    "companyCurrencyAmount": 0.0,
    "sourceCurrencyAmount": 0.0,
    "documentDate": "2013-04-04T00:00:00",
    "documentType": "PMI",
    "invoicingStatus": "POS",
    "documentNo": "XXXXXX",
    "company": 10001,
    "documentCurrency": "USD",
    "documentText": "text here",
    "businessPartner": 20002,
    "documentLinesFromDocument":
    [
        {
            "documentAmount": 0.0,
            "companyCurrencyAmount": 0.0,
            "sourceCurrencyAmount": 0.0,
            "sourceCurrency": "USD",
            "refDocument": "52011962",
            "documentLineText": "text here",
            "isAccountsPayable": "true",
            "businessPartner": "16959"
        }
    ]
}
```

## **Generic Dataloy API Fields**

The following fields exist for all Dataloy VMS API resources:

| Field Name       | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **key**          | <p>The ID of the entity. This can be used to:</p><ul><li>request that entity at a URL of the form <strong>/Entitytype/{key}</strong></li><li>or to represent the entity in a <strong>POST</strong> or <strong>PUT</strong> request</li></ul>                                                                                                                                                                                                                 |
|                  | The full URL of the entity.                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| **modifiedDate** | <ul><li>Last Modified Date</li><li>Object Changed by User or Recalculated by System</li></ul>                                                                                                                                                                                                                                                                                                                                                                |
| **createdDate**  | Date for Object Creation                                                                                                                                                                                                                                                                                                                                                                                                                                     |
|                  | <p>Defines the code property of a resource. The value is the name of another property which can be used to identify the resource and is, in many cases, functionally equivalent to the "key" propery.</p><p><em><strong>Note</strong>: Not all resources have a codeProperty.</em></p><p>Example:</p><p>When setting a currency either an invoice the key (ID) of that currency or the currencyCode (i.e. the codeProperty of Currency) can be used.<br></p> |
| **createdById**  | User key of the Dataloy VMS user that created the resource instnce initially.                                                                                                                                                                                                                                                                                                                                                                                |
| **changedById**  | User key of the Dataloy VMS user that updated the resource instance.                                                                                                                                                                                                                                                                                                                                                                                         |
| **remarks\[]**   | Array of remarks connected to the resouce instance                                                                                                                                                                                                                                                                                                                                                                                                           |

## **Date Format**

**From version 2.0.0 the date format has been changed to conform ISO 8601:**

yyyy-MM-ddThh:mm:ss\
\
Example: \
\
*2014-01-01T00:00:00*

**Versions prior to 2.0.0:**

Date format for JSON messages: yyyy-MM-dd hh:mm:ss\
\
Example:\
\
*2014-01-01 00:00:00*\
Date format for [filtering](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414908/Filtering): yyyy-MM-ddThh:mm:ss\
\
Example: \
\
*2014-01-01T00:00:00*

## **REST - Representational State Transfer**

A quick introduction to **REST** is available at <http://www.infoq.com/articles/rest-introduction>[.](http://www.infoq.com/articles/rest-introduction)

## **JSON - JavaScript Object Notation**

JSON is a text format that is natively supported by Javascript. It is less verbose than XML and is easier for users to read. JSON is not written in order, so fields might change position between calls. A quick introduction:  <http://www.json.org/>&#x20;

## **Tools for Simple Tests**

Several tools are available to aid the testing of the API. This enables a payload to be sent to a URL **with a specific type of request**, for example, GET, PUT, POST.

Examples of available tools (but NOT limited to):

*Chrome:*

* *Advanced REST client:* [*https://chrome.google.com/webstore/search/advanced%20rest%20client*](https://chrome.google.com/webstore/search/advanced%20rest%20client?utm_source=chrome-ntp-icon)
* *Postman:* [*https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en-US*](https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en-US)

*Firefox:*

* *Poster:* [*https://addons.mozilla.org/en-us/firefox/addon/poster/*](https://addons.mozilla.org/en-us/firefox/addon/poster/)&#x20;

***Note**: Dataloy recommends tools like JSONView to Chrome (to browse the API more conveniently when developing).*

Documentation of API resources is currently in progress. Presently the reference documentation is manually updated. (*More Information:* [*Accounting Integration API*](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414837/Accounting+Integration+API)).\ <br>


# Data Model

{% embed url="<https://dataloy-systems.stoplight.io>" %}


# Filtering

**Dataloy REST API** uses a generic search/filtering functionality. In general, **all resources** supports filtering on **all properties** of that resource and linked resources (for exceptions, see [Limitations](#limitations)).

## **Syntax**

The filter query parameter has the following format:&#x20;

| `<Base URL>/<Resource>?filter=<json property>(OPERATOR)<value>` |
| --------------------------------------------------------------- |

Example that will return currency information for USD:

| `localhost/ws/rest/Currency?filter=currencyCode(EQ)USD` |
| ------------------------------------------------------- |

### Syntax Breakdown  **\<Base URL>**

For more information see [Getting Started with Dataloy REST API](/api-release-8.26/dataloy-rest-api/getting-started)\
&#x20;

**\<Resource>**&#x20;

Can be any of the [Resources](/api-release-8.26/dataloy-rest-api/data-model) available in the Dataloy API.

**\<json property>**&#x20;

Can be any json **property** of the [resource](/api-release-8.26/dataloy-rest-api/data-model) (for exceptions, see [Limitations](#limitations)).\ <br>

## **\<OPERATOR>**&#x20;

The operator is always:

* surrounded by parenthesis
* is always upper case

### **List of Operators**

<table data-full-width="true"><thead><tr><th>Operator</th><th>Description</th><th>API Version</th><th>Example</th></tr></thead><tbody><tr><td>(EQ)</td><td>Equals Exact Value, <em>case sensitive</em></td><td></td><td>Get a Document with document number 2707374: <strong>Document?filter=documentNo(EQ)2707374</strong></td></tr><tr><td>(NE)</td><td>Not Equal</td><td></td><td>Get all Documents not in company 1000: <strong>Document?filter=company.companyCode(NE)1000</strong></td></tr><tr><td>(GT)</td><td><p>Greater Than</p><p><em>ONLY numeric and date values</em></p></td><td></td><td>Get all Voyages modified since 2014-01-01 00:00:00, not including 2014-01-01 00:00:00: <strong>Voyage?filter=modifiedDate(GT)2014-01-01T00:00:00</strong></td></tr><tr><td>(GTE)</td><td><p>Greater Than or Equal</p><p><em>ONLY numeric and date values</em></p></td><td></td><td>Get all Voyages modified since 2014-01-01 00:00:00, including 2014-01-01 00:00:00: <strong>Voyage?filter=modifiedDate(GTE)2014-01-01T00:00:00</strong></td></tr><tr><td>(LT)</td><td><p>Lesser Than</p><p><em>ONLY numeric and date values</em></p></td><td></td><td>Get all Documents that has document amount less than 100000: <strong>Document?filter=documentAmount(LT)100000</strong></td></tr><tr><td>(LTE)</td><td><p>Lesser Than or Equal</p><p><em>ONLY numeric and date values</em></p></td><td></td><td>Get all Documents that has document amount less than 100000, including 100000: <strong>Document?filter=documentAmount(LT)100000</strong></td></tr><tr><td>(IN)</td><td>Equals One of the Elements in a Given List</td><td></td><td>Get all Documents that are ready for posting and has status type INI, INO, CRI or CRO: <strong>Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&#x26;filter=invoicingStatus.statusTypeCode(IN)(INI,INO,CRI,CRO)</strong></td></tr><tr><td>(NULL)</td><td>Filter for NULL values</td><td>2.10</td><td>Get all Documents without business partner: <strong>Document?filter=businessPartner(NULL)</strong></td></tr><tr><td>(NOTNULL)</td><td>Filter for NOT NULL values</td><td>2.10</td><td>Get all Voyages with vessel: <strong>Voyage?filter=vessel(NOTNULL)</strong></td></tr><tr><td>(LK)</td><td>Like operator</td><td>3.3</td><td>Get all BunkerOrder with externalReferenceNo containing the string "test" case sensitive: <strong>BunkerOrder?filter=externalReferenceNo(LK)test</strong></td></tr><tr><td>(LKIC)</td><td>Like ignore case operator</td><td>3.3</td><td>Get all BunkerOrder with externalReferenceNo containing the string "test" case insensitive<strong>: BunkerOrder?filter=externalReferenceNo(LKIC)test</strong></td></tr><tr><td>(NLK)</td><td>Not like </td><td>8.5</td><td>Get all BunkerOrder with externalReferenceNo not containing the string "test" case sensitive: <strong>BunkerOrder?filter=externalReferenceNo(NLK)test</strong></td></tr><tr><td>(NLKIC)</td><td>Not like ignore case</td><td>8.5</td><td>Get all BunkerOrder with externalReferenceNo not containing the string "test" case insensitive: <strong>BunkerOrder?filter=externalReferenceNo(NLK)test</strong></td></tr><tr><td>(NOTIN)</td><td>Is not one of the elements in a given list</td><td>8.13</td><td>Get all Documents that are ready for posting and has status type other than CRI or CRO: Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&#x26;filter=invoicingStatus.statusTypeCode(NOTIN)(CRI,CRO)</td></tr></tbody></table>

### **\<value>**

* **Numeric Values** are straight forward. Can be integers or decimal numbers using a dot as decimal point. <br>
* **Dates** must be specified in the format: **yyyy-MM-ddTHH:mm:ss**
* **Strings** *can* be surrounded by double quotes, but it is generally not necessary. Even if the string has spaces.
* **Boolean** must be specified with 0 for false and 1 for tru&#x65;**.**

## **Combining Filters**

The filter URL parameter can be added multiple times to filter on multiple properties in one request. To do so, add a new filter parameter to the end of the URL

### **Syntax for Combining Filters**

| `<Base URL>/<Resource>?filter=<json property>(OPERATOR)<value>&filter=<json property 2>(OPERATOR)<value>` |
| --------------------------------------------------------------------------------------------------------- |

Example:

| `<Base URL>/Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&filter=invoicingStatus.statusTypeCode(IN)(INI,INO,CRI,CRO)` `Invoices ready to be transferred to accounting will be returned.` |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |

### **Properties for Sub Objects**

Filters can be used for sub objects by using a "dot path". Example of a sub object is commodity on Cargo:

```
Part of the Cargo resource as an example:
  
{
    "cargoReference": 12345,
    "freight": 20000,
    "cargoQuantity":100000,
    "commodity": {
            "commodityName": "Steel",
            "commodityCode": "10000",
            "key": 1069734,
            "self": "http://localhost:8080/ws/rest/Commodity/1069734"
    }
}
```

To search for cargoes with commodity steel:

| `<Base URL>/Cargo?filter=commodity.commodityCode(EQ)10000` |
| ---------------------------------------------------------- |

### **Limitations**

The following properties are currently not possible for filtering:

* self
* remarks

A few other properties are unsupported, these are documented for each resource.

## **Examples**

**Cargo**

Get Cargo with freight more than 1000000 and freightCurrency USD or EUR:

| `/Cargo?filter=freight(GT)1000000&filter=freightCurrency.currencyCode(IN)USD,EUR` |
| --------------------------------------------------------------------------------- |

**Document**

Get Documents with documentType "INV" and invoicingStatus "PEN"

| `/Document?filter=documentType.documentType(EQ)INV&filter=invoicingStatus.statusTypeCode(EQ)PEN` |
| ------------------------------------------------------------------------------------------------ |

**Voyage**&#x20;

Get Voyages for the vessel with vessel code ABRA

| `/Voyage?filter=voyageHeader.vesselCode.vesselCode(EQ)ABRA` |
| ----------------------------------------------------------- |

Get Voyage with reference number VES100

| `/Voyage?filter=voyageHeader.referenceNo(EQ)VES100` |
| --------------------------------------------------- |

Get Voyage with start date > 01.01.2016 and operator is user with userCode "BAK"

| `/Voyage?filter=voyageHeader.voyageStartDate(GT)2016-01-01T00:00:00&voyageHeader.operator.userCode(EQ)BAK` |
| ---------------------------------------------------------------------------------------------------------- |

Get Voyages that are operational for vessel ABRA

| `/Voyage?filter=voyageHeader.voyageStatus.statusTypeCode(EQ)OPR&filter=voyageHeader.vesselCode.vesselCode(EQ)ABRA` |
| ------------------------------------------------------------------------------------------------------------------ |

Get all Voyages that has Oslo as Load Port in 2015

| `/Voyage?filter=portCalls.reasonForCall.reasonForCall(EQ)L&filter=portCalls.port.portName(EQ)OSLO&filter=voyageHeader.voyageStartYear(EQ)2015` |
| ---------------------------------------------------------------------------------------------------------------------------------------------- |


# Sorting

It is possible sort the result of any search. The following type of sorting are supported:

* ASCENDING (ascending order,  case - or database sensitive)
* ASCENDING INSENSITIVE (ascending order, case-insensitive)
* DESCENDING (descending order, case - or database - sensitive)
* DESCENDING INSENSITIVE (descending order, case-insensitive)

ASCENDING

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(AS)>

ASCENDING INSENSITIVE

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(ASI)>

DESCENDING&#x20;

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(DS)>

DESCENDING INSENSITIVE

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(DSI>)

&#x20;

It is possible use sorting in combination with any filter and pagination:

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(DSI)&filter=flag.countryCode(EQ)HK&pageNumber=4&limit=10>\
\
Calculated fields are sorted after data retrieval and only consider records in the response. See the data model documentation for field specifications: <https://dataloy-systems.stoplight.io/>


# Pagination

To return a defined number of objects for any Dataloy resource it has to be specified in the URL the page number, **pageNumber** parameter, and the number of objects that the page has to contain, **limit** parameter. For example:

[\
/ws/rest/Document?pageNumber=1\&limit=10\&filter=documentAmount(GT)100000](http://localhost:8080/ws/rest/Document?\&pageNumber=1\&limit=10\&filter=documentAmount\(GT\)100000)

it will return the first page containing at max 10 Document objects having the property documentAmount greater than 100000. In the response will be added an header parameter called **totalObjectsNumber** that indicates the total number of objects of the endpoint.

From **API 5.18** is possible to avoid to get **totalObjectsNumber**  sending the HTTP header parameter **noCount = YES,** this will allow a bit better performance.

Another example:

[/ws/rest/Vessel?filter=flag.countryCode(EQ)HK\&pageNumber=4\&limit=10](http://localhost:8080/ws/rest/Vessel?filter=flag.countryCode\(EQ\)HK\&pageNumber=4\&limit=10)

<br>

it will return the fourth page containing at max 10 Vessels objects having the countryCode property equals to EQ.


# Adjust Number of Fields to be Returned from a Request

**I**t is possible to adjust the number of fields that have to be returned from a resource. It's possible to both increase and decreases the number of fields from the default view. So if only field A and B from a resource is needed and the other X number of fields can be ignored, it can be specified in the header of the request. This will reduce the overhead of data transferred and improve performance. If more fields are needed in one request, to avoid making a second request to get all the data that is needed, this can also be done. So if fields A, B and C are returned in the default view, but also field D is needed, this can be specified in the header.

## **Customize the Number of Fields returned**

Retrieving data from a resource may provide more information than needed. Fields with data to be returned can be specified by first adding a header field and then specifying the fields to be returned in the header field value. The header field value is specified as a **JSON message** following the same structure as the resource structure that is used when making the request. This enables fields to be specified in main- and sub-objects. &#x20;

The examples listed illustrate how it is used for a business partner. The procedure is, however, the same for all resources. The key and self attribute will always be returned, but the number of displayed/hidden fields can be customized.

Business Partner without any field restriction will result in ( *view example*):

```
{
    "businessPartnerName": "Big Customer",
    "businessPartnerSort": "BIG.",
    "businessPartnerCode": "45999",
    "codeProperty": "businessPartnerCode",
    "bankAccounts": [],
    "individuals": [],
    "user": null,
    "createdDate": "2014-01-27T18:38:52",
    "changedById": 3689599,
    "createdById": 1045293,
    "externalObjectKey": null,
    "modifiedDate": "2024-09-29T10:59:34",
    "portAgentType": null,
    "bankAccount": null,
    "paymentTerms": {
        "key": 1004281,
        "self": "https://dev.dataloy.com/ws/rest/PaymentTerms/1004281"
    },
    "businessUnit": {
        "key": 1000576,
        "self": "https://dev.dataloy.com/ws/rest/BusinessUnit/1000576"
    },
    "baselineTerm": {
        "key": 1004265,
        "self": "https://dev.dataloy.com/ws/rest/BaselineTerm/1004265"
    },
    "contactInfo": [
        {
            "key": 5987711,
            "self": "https://dev.dataloy.com/ws/rest/ContactInfo/5987711"
        }
    ],
    "businessPartnerName2": null,
    "companyRegistrationNo": "987987987",
    "isInterCompany": false,
    "isTotalCommissionPayable": false,
    "maxAdvancePaymentPercent": 100,
    "rating": null,
    "ratingExpiryDate": null,
    "vatNumber": null,
    "addresses": [
        {
            "key": 5993125,
            "self": "https://dev.dataloy.com/ws/rest/Address/5993125"
        }
    ],
    "businessPartnerLink": {
        "key": 1004433,
        "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1004433"
    },
    "businessPartnerType": {
        "key": 1000032,
        "self": "https://dev.dataloy.com/ws/rest/BusinessPartnerType/1000032"
    },
    "companyBankAccount": null,
    "www": [
        {
            "key": 5987713,
            "self": "https://dev.dataloy.com/ws/rest/Www/5987713"
        }
    ],
    "payee": {
        "key": 1004433,
        "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1004433"
    },
    "remarks": [],
    "isObjectActive": true,
    "key": 1045574,
    "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1045574"
}

```

**Examples**

1\. Return Business Partner name only:

**fields: {"businessPartnerName":"\*"}**

```
{
  "businessPartnerName": "Big Customer",
  "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1045574",
  "key": 1045574
}
```

2\. Return address1 only:

**fields: {"addresses": {"address1":"\*"}}**

{% hint style="danger" %}
Note that addresses is an array, but for the fields value it should be treated as a field, so do not include \[ ]
{% endhint %}

```
{
  "addresses": [
    {
      "address1": "Halfdan Kjerulfs gate 4",
      "key": 5993125,
      "self": "https://dev.dataloy.com/ws/rest/Address/5993125"
    }
  ],
  "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1045574",
  "key": 1045574
}
```

3\. Return Business Partner name and address1:

**fields: {"businessPartnerName":"\*", "addresses":{"address1":"\*"}}**

```
{
  "businessPartnerName": "Big Customer",
  "addresses": [
    {
      "address1": "Halfdan Kjerulfs gate 4",
      "key": 5993125,
      "self": "https://dev.dataloy.com/ws/rest/Address/5993125"
    }
  ],
 "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1045574",
 "key": 1045574
}
```


# Webhooks

#### Webhooks <a href="#webhooks-webhooks" id="webhooks-webhooks"></a>

Webhooks are user-defined HTTP callbacks that receive events for the subscribed event types. Webhook notifications are asynchronous, the order is not guaranteed.

Events are categorised into event types. Events occur due to changes in the state of a resource, such as when a voyage is updated. When an event occurs, the registered applications are notified via HTTP POST. The POST contains the event details, including the event type that caused the event.&#x20;

When an application receives the event, it must respond with a 200-level HTTP status code.

#### **Subscription** <a href="#webhooks-subscription" id="webhooks-subscription"></a>

When a webhook subscription is made, through the resource WebhookSubscription, for a Dataloy object, BunkerOrder for instance, the subscribed webhook will be pushed with all the changes that occurred to the subscribed object and its object hierarchy. So if a PortCall of the subscribed BunkerOrder is updated the webhook will be notified.

{% hint style="danger" %}
The Remarks are not part of the webhook process. It is not possible to get notifications of changes in Remarks.
{% endhint %}

The Dataloy webhook event type is a concatenation of the following attributes:

* Resource name (Document, Voyage, ..)
* Operation type (C,U, D create, update, delete)
* Object key

\
The user can subscribe to a webhook for a given event, for example:

| Cargo.C         | Notifies when a Cargo is created                                 |
| --------------- | ---------------------------------------------------------------- |
| Document.D      | Notifies when a Document is deleted.                             |
| Voyage.U        | Notifies when a Voyage is updated.                               |
| Voyage.U.793628 | Will notify when voyage, having voyage.key = 793628, is updated. |

{% hint style="danger" %}
**Automatic Deactivation of subscription**

If the subscribing system is unavailable or takes too long to respond, the server will deactivate the subscription after attempting 5 times (once a minute). The number of attempts and the interval between each attempt can be configured.

Deactivated subscriptions cannot be reactivated, a new subscription must be created if needed.&#x20;

***Email alert when a subscription is de-activated:** Add the desired email address (e.g. to the IT ops team) to the API user (in User Administration) to receive an email notification if a subscription is de-activated.*
{% endhint %}

The message sent to the subscribed endpoint is set in the body of the POST method. The message is a JSON object and has the following structure:

```
{
 "id": "1573335-244070007",
 "eventTime": "2016-09-14T13:37:26",
 "objectType": "PortCall",
 "eventType": "U",
 "dataloyObject":189126972,
 "dataloyObjectSelf":"http://localhost:8080/ws/rest/PortCall/7823672"
 "subscription":{
            "key":243885046,
            "self":"http://localhost:8080/ws/rest/WebhookSubscription/243885046"
            "objectType":"BunkerOrder",
            "dataloyObject":244070007,
            "eventType": "U",
             "url":"http://test1.dataloy.com:8080/webhook/"
   }
"resource":{ 
      "key":244070007,
      "self":"http://localhost:8080/ws/rest/BunkerOrder/244070007",
      "vessel":{ 
         "vesselName":"VESSEL1",
         "key":188616815,
         "self":"http://localhost:8080/ws/rest/Vessel/188616815"
      },
      "currency":{ 
         "currencyCode":"USD",
         "currencyName":"U.S. DOLLAR",
         "key":400132,
         "self":"http://localhost:8080/ws/rest/Currency/400132"
      },
      "exchangeRate":3.0,
      "modifiedDate":"2016-09-21T06:38:29",
      "portCall":{ 
         "key":189126972,
         "self":"http://localhost:8080/ws/rest/PortCall/189126972",
         "eventLogs":[ 
            { 
               "key":189126978,
               "self":"http://localhost:8080/ws/rest/EventLog/189126978",
               "event":{ 
                  "key":1000052,
                  "self":"http://localhost:8080/ws/rest/Event/1000052",
                  "eventCode":"DEP",
                  "eventDesc":"Departed"
               },
               "eventLogDate":"2015-02-13T17:18:00"
            },
            { 
               "key":189126974,
               "self":"http://localhost:8080/ws/rest/EventLog/189126974",
               "event":{ 
                  "key":1000050,
                  "self":"http://localhost:8080/ws/rest/Event/1000050",
                  "eventCode":"ARR",
                  "eventDesc":"Arrived"
               },
               "eventLogDate":"2015-02-06T20:18:00"
            },
            { 
               "key":189126976,
               "self":"http://localhost:8080/ws/rest/EventLog/189126976",
               "event":{ 
                  "key":1000051,
                  "self":"http://localhost:8080/ws/rest/Event/1000051",
                  "eventCode":"BRT",
                  "eventDesc":"Berthed"
               },
               "eventLogDate":"2015-02-07T10:06:00"
            }
         ]
      },
      "extraCost":0.0,
      "bunkeredDate":"2016-01-01T00:00:00",
      "orderDate":"2016-09-06T10:16:36",
      "bunkerPaidBy":null,
      "createdDate":"2016-09-21T06:12:42",
      "createdById":999999,
      "bunkerOrderStatus":{ 
         "key":243093653,
         "self":"http://localhost:8080/ws/rest/StatusType/243093653",
         "statusTypeDesc":"Requirement",
         "statusTypeCode":"REQBO"
      },
      "externalReferenceNo":null,
      "bunkerOrderLines":[ 
         { 
            "key":244070009,
            "self":"http://localhost:8080/ws/rest/BunkerOrderLine/244070009",
            "minQuantity":50.0,
            "maxQuantity":100.0,
            "extraCost":0.0,
            "bunkeredQuantity":111.0,
            "unitPrice":100.0,
            "bunkerType":{ 
               "key":73564540,
               "self":"http://localhost:8080/ws/rest/BunkerType/73564540",
               "isoCode":null,
               "isoYear":null,
               "bunkerTypeCode":"FO",
               "bunkerTypeDesc":"FO",
               "sulphurPercent":null
            }
         }
      ],
      "company":null,
      "bunkerBroker":{ 
         "businessPartnerName":"BUSINESS PARTNER 1",
         "businessPartnerSort":"BUSINESS PARTNER 1",
         "businessPartnerCode":"1111",
         "businessPartnerType":{ 
            "businessPartnerType":"BS",
            "businessPartnerTypeDesc":"Bunker Supplier",
            "key":1000034,
            "self":"http://localhost:8080/ws/rest/BusinessPartnerType/1000034"
         },
         "key":39697371,
         "self":"http://localhost:8080/ws/rest/BusinessPartner/39697371"
      },
      "bunkerAccountOf":null,
      "bunkerSupplier":{ 
         "businessPartnerName":"BUSINESS PARTNER 2",
         "businessPartnerSort":"BUSINESS PARTNER 2",
         "businessPartnerCode":"22222",
         "businessPartnerType":{ 
            "businessPartnerType":"BS",
            "businessPartnerTypeDesc":"Bunker Supplier",
            "key":1000034,
            "self":"http://localhost:8080/ws/rest/BusinessPartnerType/1000034"
         },
         "key":39697206,
         "self":"http://localhost:8080/ws/rest/BusinessPartner/39697206"
      },
      "remarks":[ 
 
      ]
   }
}
```

The attributes have the following meaning:

| id                | Unique identifier of the notification                                                                                                                          |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| eventTime         | The time when the event occurred                                                                                                                               |
| objectType        | Name of the changed Dataloy object                                                                                                                             |
| dataloyObject     | The primary key of the changed Dataloy object (it can be different from the subscribed object, it can be an object in the hierarchy of the subscribed object ) |
| eventType         | C for creation, U for update, D for deletion                                                                                                                   |
| dataloyObjectSelf | the Dataloy URL of the changed object                                                                                                                          |
| subscription      | Subscription data:                                                                                                                                             |
| resource          | The JSON of the DataloyObject that the subscription refers to                                                                                                  |

### New functionalities since [version 3.9](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404308/Dataloy+API+3.9.0+Release+Notes) <a href="#webhooks-newfunctionalitiessinceversion3.9" id="webhooks-newfunctionalitiessinceversion3.9"></a>

With API 3.9 the following new functionalities have been introduced:

* Possibility to be notified  of changes via email
* Possibility to customize the JSON pushed as [Adjust Number of Fields to be Returned from a Request](/api-release-8.26/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request)
* Possibility to filter  changes that have to be pushed via expressions
* Possibility to filter  changes that have to be pushed via scripts

#### Notifications via email <a href="#webhooks-notificationsviaemail" id="webhooks-notificationsviaemail"></a>

To be notified via email in the WebhookSubscription must be specified the **channelInfo** property with **channelType** **EMAIL** and the **URL** with the email address:

```
{
       "channelInfo": {
           "url": "info@dataloy.com",
           "channelType": "EMAIL"
       }
   }
```

channelType can be EMAIL or HTTP if HTTP is set the URL attribute must contain the endpoint where to push notifications.

#### Possibility to customize the JSON pushed <a href="#webhooks-possibilitytocustomizethejsonpushed" id="webhooks-possibilitytocustomizethejsonpushed"></a>

Through the attribute **JSON** of WebhookSubscription is possible to specify which attributes of the object must be pushed (see [Adjust Number of Fields to be Returned from a Request](/api-release-8.26/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request)). The value of JSON must be encoded with Base64.

For instance, if the subscription is for the object BunkerOrderLine a possible value for the JSON attribute could be:

```
{"extraCost":"*"}
```

that encoded will be&#x20;

```
"json": "ew0KCSJleHRyYUNvc3QiOiIqIg0KfQ=="
```

In this way the sub-object in the attribute **resource**  will be smaller:

```
{ 
   "id":"245-320996749",
   "eventTime":"2018-01-30T10:42:11",
   "eventType":"U",
   "objectType":"BunkerOrderLine",
   "dataloyObject":320996749,
   "dataloyObjectSelf":"http://platform-dev.dataloy.com:80/ws/rest/BunkerOrderLine/320996749",
   "subscription":{ 
      "key":332501529,
      "self":"http://platform-dev.dataloy.com:80/ws/rest/WebhookSubscription/332501529",
      "isSubscriptionActive":true,
      "user":{ 
         "key":999999,
         "self":"http://platform-dev.dataloy.com:80/ws/rest/User/999999",
         "userCode":"DATALOY",
         "userName":"dataloy"
      },
      "objectType":null,
      "dataloyObject":null,
      "url":null,
      "dlpAlertScript":{ 
         "key":318269643,
         "self":"http://platform-dev.dataloy.com:80/ws/rest/DlpAlertScript/318269643",
         "scriptCode":"BUP",
         "scriptName":"Bunkered Unit Price updated"
      },
      "eventType":null,
      "unsubscriptionDate":null,
      "channelInfo":{ 
         "key":332501528,
         "self":"http://platform-dev.dataloy.com:80/ws/rest/ChannelInfo/332501528",
         "channelType":{ 
            "key":311504704,
            "self":"http://platform-dev.dataloy.com:80/ws/rest/ChannelType/311504704",
            "channelTypeCode":"EMAIL"
         },
         "url":"ab@dataloy.com"
      }
   },
   "resource":{ 
      "key":320996749,
      "self":"http://platform-dev.dataloy.com:80/ws/rest/BunkerOrderLine/320996749",
      "extraCost":0.0
   }
}
```

#### Possibility to filter  changes that have to be pushed via expressions <a href="#webhooks-possibilitytofilterchangesthathavetobepushedviaexpressions" id="webhooks-possibilitytofilterchangesthathavetobepushedviaexpressions"></a>

Through the attribute **expression** of WebhookSubscription is possible to write a **Java expression** against the object changed. At runtime If the expression return true the notification will be sent,  otherwise no.

For instance, if the subscription is done for the object BunkerOrderLine a possible expression could be:

| `dlpObject.getUnitPrice()!=null` `&& ( dlpObject.getUnitPrice()>10` `\|\|  dlpObject.getUnitPrice()<100)` |
| --------------------------------------------------------------------------------------------------------- |

that for any changes at any BunkerOrderLine object will check if the unit price is not null and its value is between 10 and 100, if yes the notification will be sent.&#x20;

In the expression must be used the variable **dlpObject** to refer to the changed object, the object will contain the new values. If the expression needs to check also the previous values of the object, the variable **oldDlpObject** can be used.

For instance:

| `oldDlpObject.getExtraCost()!=null` `&& dlpObject.getExtraCost()!=null` `&& dlpObject.getExtraCost()> oldDlpObject.getExtraCost()` |
| ---------------------------------------------------------------------------------------------------------------------------------- |

that will check if the new extra cost of a BunkerOrder is greater than the previous one.

If you want to be notified when an attribute change value from null to not null:

| `oldDlpObject.getReferenceNo() == null` `&& dlpObject.getReferenceNo() != null` |
| ------------------------------------------------------------------------------- |

**The old values will be accessible only for those Dataloy object changed via Dataloy API.**

#### Possibility to filter  changes that have to be pushed via scripts <a href="#webhooks-possibilitytofilterchangesthathavetobepushedviascripts" id="webhooks-possibilitytofilterchangesthathavetobepushedviascripts"></a>

Contact Dataloy to have info regarding scripts.

### New functionalities since [version 3.16](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404337/Dataloy+API+3.16.0+Release+Notes) <a href="#webhooks-newfunctionalitiessinceversion3.16" id="webhooks-newfunctionalitiessinceversion3.16"></a>

In version 3.16 (and later) it is possible to decide if a webhook subscription should only be  notified on changes to the object subscribed. So for instance making a subscription for the Voyage object, the changes that will occur to linked objects, like PortCall, Cargo, etc, will be not notified. To achieve this behaviour a new boolean attribute called **onlyMainObject** in WebhookSubscription has been added, setting it to true only the changes for the subscribed will be sent.

A new endpoint in WebhookSubscription **POST:sendFailedNotifications** has been added to resend manually the failed webhook notification.

### New functionalities since version 5.23 <a href="#webhooks-newfunctionalitiessinceversion5.23" id="webhooks-newfunctionalitiessinceversion5.23"></a>

In version 5.23 (and later) it is possible to decide if a webhook subscription should only be notified with the raw object, without the envelope payload.  To achieve this behavior a new boolean attribute called **rawObject** in WebhookSubscription has been added, setting it to true the raw object will be sent.

### New functionalities since version 5.24 <a href="#webhooks-newfunctionalitiessinceversion5.24" id="webhooks-newfunctionalitiessinceversion5.24"></a>

A new attribute **xsl** has been added which allows you to store an XSL stylesheet to transform the subscribed object to XML. The value of the field must be encoded with Base64. This is part only of Enterprise API.

### New functionalities since version[ ](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404337/Dataloy+API+3.16.0+Release+Notes)6.44 <a href="#webhooks-newfunctionalitiessinceversion3.16" id="webhooks-newfunctionalitiessinceversion3.16"></a>

In order to not get notified by the changes done by the user of the subscription the attribute **notSendMyChanges** can be set to true.

### Supported Methods <a href="#webhooks-supportedmethods" id="webhooks-supportedmethods"></a>

**GET /WebhookSubscription**

Get a list of WebhookSubscription objects. Filter to avoid huge amounts of data (*see* [*Filtering* ](/api-release-8.26/dataloy-rest-api/filtering)*documentation for examples*). &#x20;

**GET /WebhookSubscription/{key}**

Get a single WebhookSubscription object.

**Example GET Return Body**&#x20;

```
{
  "key": 243907762,
  "self": "http://localhost:8080/ws/rest/WebhookSubscription/243907762",
  "isSubscriptionActive": true,
  "unsubscribed": false,
  "eventType": "U",
  "dataloyObject": 243896793,
  "createdDate": "2016-09-16T08:35:46",
  "modifiedDate": "2016-09-16T08:35:46",
  "createdById": 999999,
  "objectType": "BunkerOrder",
  "user": {
    "key": 999999,
    "self": "http://localhost:8080/ws/rest/User/999999",
    "userName": "dataloy",
    "userCode": "DATALOY"
  },
  "url": "http://test1.dataloy.com:8080/webhook/",
  "unsubscriptionDate": null,
  "webhookUsername": null,
  "webhookPassword": null,
  "remarks": []
}
```

since API 3.9:

```
{
    "key": 320298564,
    "self": "http://platform-dev.dataloy.com:80/ws/rest/WebhookSubscription/320298564",
    "isSubscriptionActive": true,
    "unsubscribed": false,
    "user": {
        "key": 999999,
        "self": "http://platform-dev.dataloy.com:80/ws/rest/User/999999",
        "userCode": "DATALOY",
        "userName": "dataloy"
    },
    "objectType": "BunkerOrder",
    "createdDate": "2018-01-11T10:53:14",
    "url": "http://platform-dev.dataloy.com/ws/rest/dataloy/sendJson",
    "modifiedDate": "2018-01-11T10:53:14",
    "createdById": 999999,
    "dataloyObject": null,
    "expression": null,
    "dlpAlertScript": null,
    "eventType": "U",
    "unsubscriptionDate": null,
    "scriptParameterValues": [],
    "useMsg": false,
    "json": "{}",
    "webhookPassword": "XXX",
    "webhookUsername": "dataloy",
    "channelInfo": null,
    "remarks": []
}
```

**POST /WebhookSubscription**

Create a new WebhookSubscription.

**Examples**

Create a subscription to get notifications when the BunkerOrder with primary key 243896793 is updated:

```
{
    "eventType":"U",
    "user":999999,
    "objectType":"BunkerOrder",
    "dataloyObject":243896793,
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when any BunkerOrder is updated:

```
{
    "eventType":"U",
    "user":999999,
    "objectType":"BunkerOrder",
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when a BunkerOrder is created:&#x20;

```
{
    "eventType":"C",
    "user":999999,
    "objectType":"BunkerOrder",
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when the BunkerOrder with primary key 243896793 is deleted:&#x20;

```
{
    "eventType":"D",
    "user":999999,
    "objectType":"BunkerOrder",
    "dataloyObject":243896793,
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when any BunkerOrder is deleted:&#x20;

```

{
    "eventType":"D",
    "user":999999,
    "objectType":"BunkerOrder",
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when any BunkerOrder is updated  via email, since API 3.9:

```
{
    "eventType":"U",
    "user":999999,
    "objectType":"BunkerOrder",
    "channelInfo":{ 
         "url": "info@dataloy.com",
         "channelType": "EMAIL"
    }
}
```

Create a subscription to get notifications only when a Voyage object is changed, since API 3.16:

```
{
    "eventType":"U",
    "user":999999,
    "objectType":"Voyage",
    "channelInfo":{ 
         "url": "info@dataloy.com",
         "channelType": "EMAIL"
    },
    "onlyMainObject": true
}
```

**PUT /WebhookSubscription/{key}**

Only the following attributes can be updated:

* unsubscribed
* url
* webhookUsername
* webhookPassword

Since API 3.9 is possible to change also these other attributes:

* channelInfo
* json
* expression
* dlpAlertScript
* scriptParameterValues
* useMsg

To unsubscribe a subscription the following JSON must be sent. It is not possible to update the subscription if it has been unsubscribed:

```
{
    "unsubscribed": true   
}
```

**DELETE /WebhookSubscription/{key}**

To delete a WebhookSubscription first it has to be unsubscribed. **It is not possible to delete** **WebhookSubscription that got Webhook notifications, regardless that it has been unsubscribed or not**.


# Expression Builder

## Overview

The Expression Builder is a visual tool for creating webhook filters without writing code. Filter your webhook notifications to only receive updates that match specific criteria.

**Available when creating and maintaining:**

* Webhook subscriptions [(API documentation)](/api-release-8.26/dataloy-rest-api/webhooks)
* Subscription templates

**Example**: Instead of getting notified about all voyage updates, only get notified for voyages with status "Nominated" or voyages longer than 30 days.

## Add Your First Condition

1. Click **+ Add Condition**
2. Click field to open the field selector and select a "Field" (e.g., `voyageHeader.voyageStatus.statusTypeDesc`).&#x20;
3. Choose an "Operator" (=, >, <, etc.)
4. Enter the "Value" (e.g., "Nominated")

<figure><img src="/files/rS0ceqC1ajLB1Sg0o58A" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Notice the expression preview: `voyageHeader.voyageStatus.statusTypeDesc = "Nominated"`
{% endhint %}

## Add Multiple Conditions

Click **+ Add Condition** again to add more filters:

* By default, conditions use **"Match all"** (AND logic) – both must be true
* Switch to **"Match any"** (OR logic) – either condition can be true

<figure><img src="/files/U0M2VHyyi0xNq38bllFB" alt=""><figcaption></figcaption></figure>

**Match all example**: `statusTypeDesc = "Nominated" AND daysCanal > 1`\
**Match any example**: `statusTypeDesc = "Nominated" OR daysCanal > 1`

## Create Groups for Complex Logic

Click **+ Add Group** to create parentheses around conditions:

<figure><img src="/files/mJ5YraRu9EVSxWQZJu0e" alt=""><figcaption></figcaption></figure>

**Result**: `daysCanal > 1 AND (daysTotal < 10 OR daysTotalAtSea < 5)`

## Compare to Field

Instead of comparing to a static value, you can compare one field to another field by toggling **Compare to Field**.

<figure><img src="/files/tRgpRao26egQi0dUvKb5" alt=""><figcaption></figcaption></figure>

**Use case**: Get notified when loading takes longer than discharging:

```
daysLoading > daysDischarging
```

## Previous vs Current Values

When subscribing to updates, you can compare current and previous field values:

* **Previous**: The field value before the update
* **Current**: The field value after the update

**Example**: If voyage daysLoading change from 2.3 to 2.5:

* Previous value = 2.3
* Current value = 2.5

<figure><img src="/files/5pMZRVmqrGlRBWYXYAbZ" alt=""><figcaption></figcaption></figure>

Get notified when loading days increases:

```
prev.daysLoading < daysLoading
```


# Webhooks - New functionalities

### Alerts Menu Item

Webhooks is moved out from Setup to Alerts Menu Item on VMS web. The Alerts menu group has several menu items

* Webhooks - shows the list of subscriptions made by the user if the user is a non-administrative role and shows all the subscriptions in the system for an administrator user
* Notifications - shows the list of Notifications for all the subscriptions visible for the user.

#### Webhooks&#x20;

Clicking one of the rows in webhooks, opens the webhook subscription drawer with the tabs; Overview, Notifications, Comments and attachments.  While Overview has some new additions to it, Comments remain the same from before.

<figure><img src="/files/2Zk3Cr6hVjZnwh4TLa8p" alt=""><figcaption></figcaption></figure>

* Notifications tab in the subscription drawer includes the list of notifications filtered for the selected subscription. From 6.10.0, this list is updated to be similar to the other lists on VMS web with enabled filters and sorting.

<figure><img src="/files/4H5Q6ipCtxC6m0BoMdM7" alt=""><figcaption></figcaption></figure>

* Further clicking on one of the rows in the notifications list on subscription drawer, we can see the details of the Notification Msg sent for the subscription along with the error msg if the msg sending failed.

<figure><img src="/files/UPtSiXvH4mSlhrJNfEWD" alt=""><figcaption></figcaption></figure>

## New functionality

{% tabs %}
{% tab title="Prevent Unsubscription" %}
A new attribute, called **doNotUnsubscribe** (**Prevent Unsubscription**)**,** has been added to prevent that the subscription will get unsubscribed by the system. Also if the endpoint is not reachable for more times than the max number of attempts set for the given server.&#x20;

<figure><img src="/files/sP336o2VcGoPYnZLoYYy" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Template Message" %}
Introduced the possibility for users to define a message template that should be used when sending notifications for a webhook subscription.

When creating a Webhook Subscription, provide a text string for the attribute **templateMsg**. Attributes from the updated object can be included in the notification text through the format `{{attributeName}}.`

For example, when creating a subscription on Bank object , the user can use a templateMsg like *‘Bank with Name {{bankName}} is changed by {{changedById}} .*

<figure><img src="/files/POTZCkVTHxYmnf3Hmk7F" alt=""><figcaption></figcaption></figure>

This would result in the below notification for the user (example data, for reference only)

<figure><img src="/files/Tx0fXA71e4f5Mb6Gr53o" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Custom Schedule" %}
Webhooks can be set to trigger automatically on a set schedule with the **webhookSchedule** attribute (only possible on Webhooks with Alert Scripts).

<figure><img src="/files/niPWzRZwfyepw0iw4nkI" alt=""><figcaption></figcaption></figure>

Preview of example above as part of an api request for creating a Webhook Subscription.

```
"webhookSchedule": {
    "intervalHours": 24,
    "intervalMinute": 0,
    "startupTimeHours": 12,
    "startupTimeMinutes": 0
}
```

{% endtab %}
{% endtabs %}

#### &#x20; Notifications

* Holds the list of notifications for those subscriptions which the user has access to.
  * Administrator can access all the notifications for all the subscriptions available in the system, while non admin users can access only the subscriptions for the given logged in user. For example,

<figure><img src="/files/A094xNI0PAyuki6foweA" alt=""><figcaption></figcaption></figure>


# Master data Objects

It is possible to activate and deactivate any Master Data object. A new property has been added for this purpose, **isObjectActive.**

To deactivate an object the following JSON has to be used in the PUT method:

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
	"isObjectActive": false
}
</code></pre></td></tr></tbody></table>

\
To activate an object the following JSON has to be used in the PUT method:

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
	"isObjectActive": true
}
</code></pre></td></tr></tbody></table>

Master Data objects has to be deactivated before they can be deleted.

{% hint style="info" %}
Deactivated objects are not included in standard Master Data list query results. To work with these objects:

#### Retrieving Deactivated Objects

* **Via List Query**: To retrieve deactivated objects in a list query, add the filter parameter `isObjectActive(EQ)false` to your request.
* **Via Direct Access**: Individual deactivated objects remain accessible by their unique key, regardless of activation status.

#### Example using BusinessPartner master data object

```
// Standard query - returns only active business partners
GET /BusinessPartner

// Query deactivated business partners
GET /BusinessPartner?filter=isObjectActive(EQ)false

// Retrieving specific deactivated business partner by key
GET /BusinessPartner/{objectKey}
```

{% endhint %}


# Attachments

Since API 3.3 Remark has a new attribute **attachments** that contains a list of Attachment objects. The Attachment resource has an attribute called **file** where can be stored the content of the file encoded in Base64.

The attribute **fileName** is mandatory, the attribute "filesize" is not mandatory but the client should pass it.

The two resources can be manipulated exactly as all other resources.

**When a new Remark is posted with attachments in the JSON the source field must be before the attachments field.**

When getting an attachment, data can be encoded in base64, but also unencoded. Attachments added from the API will be encoded and attachment added from the Java VMS client may be unencoded.

**Some examples**

Create a new remark with a file attached:

POST: [http://{URL}/ws/rest/Remark](http://localhost:8080/ws/rest/Remark)\
BODY:

```
{
  "remarkTitle": "test 1",
  "source": 19637583,
  "attachments": [
    {
      
      "file":"small file 1",
      "fileName":"test1.txt"
    }
  ]
}
```

Attach an Attachment to an existing Remark

PUT: [http://{URL}/ws/rest/Remark/244324058](http://localhost:8080/ws/rest/Remark/244324058)\
BODY:

```
{
  "attachments": [
    {
      "file":"small file 2",
      "fileName":"test2.txt"
    }
  ]
}
```


# Audit Log

The endpoint AuditLog (<https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/audit-log>) can be used to get all changes of any object in the data model.

To get the changes of a given object with key KEY\_X:

* {BASE\_URL}/ws/rest/AuditLog?filter=source(EQ)KEY\_X

In the same request send the HTTP Header parameter **fields** with this JSON

```json
{"objectName":"*","attributeName":"*","actionTime":"*","entryText":"*","source":"*","newValue":"*","oldValue":"*","isChangedByUser":"*","action":{"actionName":"*"},"user":{"userName":"*"}}
```

The response will be an array of AuditLog objects:

```json
[
    {
        "key": 8345668,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/8345668",
        "objectName": "Voyage",
        "attributeName": "ladenConsumption",
        "source": 8336217,
        "user": {
            "key": 3689599,
            "self": "https://dev.dataloy.com/ws/rest/User/3689599",
            "userName": "Andrea Biasillo"
        },
        "actionTime": "2023-03-03T19:23:00",
        "entryText": "Field update: ladenConsumption",
        "isChangedByUser": true,
        "newValue": "83.29555785678073",
        "oldValue": "67.03034584820784",
        "action": {
            "key": 1000009,
            "self": "https://dev.dataloy.com/ws/rest/Action/1000009",
            "actionName": "EDIT"
        }
    },
    {
        "key": 8345669,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/8345669",
        "objectName": "Voyage",
        "attributeName": "co2Laden",
        "source": 8336217,
        "user": {
            "key": 3689599,
            "self": "https://dev.dataloy.com/ws/rest/User/3689599",
            "userName": "Andrea Biasillo"
        },
        "actionTime": "2023-03-03T19:23:00",
        "entryText": "Field update: co2Laden",
        "isChangedByUser": true,
        "newValue": "267.045558488839",
        "oldValue": "214.89928878935433",
        "action": {
            "key": 1000009,
            "self": "https://dev.dataloy.com/ws/rest/Action/1000009",
            "actionName": "EDIT"
        }
    },
    {
        "key": 8345670,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/8345670",
        "objectName": "Voyage",
        "attributeName": "tcResultDay",
        "source": 8336217,
        "user": {
            "key": 3689599,
            "self": "https://dev.dataloy.com/ws/rest/User/3689599",
            "userName": "Andrea Biasillo"
        },
        "actionTime": "2023-03-03T19:23:00",
        "entryText": "Field update: tcResultDay",
        "isChangedByUser": true,
        "newValue": "4877.341669917246",
        "oldValue": "6227.220974136807",
        "action": {
            "key": 1000009,
            "self": "https://dev.dataloy.com/ws/rest/Action/1000009",
            "actionName": "EDIT"
        }
    },
    {
        "key": 8345671,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/8345671",
        "objectName": "Voyage",
        "attributeName": "ballastConsumption",
        "source": 8336217,
        "user": {
            "key": 3689599,
            "self": "https://dev.dataloy.com/ws/rest/User/3689599",
            "userName": "Andrea Biasillo"
        },
        "actionTime": "2023-03-03T19:23:00",
        "entryText": "Field update: ballastConsumption",
        "isChangedByUser": true,
        "newValue": "42.7633723560667",
        "oldValue": "42.90031887514484",
        "action": {
            "key": 1000009,
            "self": "https://dev.dataloy.com/ws/rest/Action/1000009",
            "actionName": "EDIT"
        }
    ]
```

The endpoint AuditLog can be used to know all the objects that have been deleted:

[/ws/rest/AuditLog?filter=action.actionName(EQ)REMOVE](https://dev.dataloy.com/ws/rest/AuditLog?filter=action.actionName\(EQ\)REMOVE\&pageNumber=1\&limit=10\&filter=actionTime\(GT\)2024-02-01T21:48:22)

in combitation with other filters and the HTTP Header parameter **fields** with this value:

{"entryText":"\*","user":"\*","actionTime":"\*"}

return a response like this one:

```json
[
    {
        "key": 18475755,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475755",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:34",
        "entryText": "Deleted LaytimeTimeSheetItem #14707386"
    },
    {
        "key": 18475756,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475756",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:34",
        "entryText": "Deleted LaytimeTimeSheetItem #14707388"
    },
    {
        "key": 18475757,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475757",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:34",
        "entryText": "Deleted LaytimeTimeSheetItem #14707389"
    },
    {
        "key": 18475758,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475758",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:34",
        "entryText": "Deleted LaytimeTimeSheetItem #14707387"
    },
    {
        "key": 18475783,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475783",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:57",
        "entryText": "Deleted LaytimeTimeSheetItem #18475759"
    },
    {
        "key": 18475784,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475784",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:57",
        "entryText": "Deleted LaytimeTimeSheetItem #18475760"
    },
    {
        "key": 18475785,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475785",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:57",
        "entryText": "Deleted LaytimeTimeSheetItem #18475761"
    },
    {
        "key": 18475802,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475802",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:38:04",
        "entryText": "Deleted LaytimeTimeSheetItem #18475780"
    },
    {
        "key": 18475803,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475803",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:38:04",
        "entryText": "Deleted LaytimeTimeSheetItem #18475781"
    },
    {
        "key": 18475804,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475804",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:38:04",
        "entryText": "Deleted LaytimeTimeSheetItem #18475782"
    }
]
```

where in the field entryText there is the object type and object key that has been deleted-


# Webhook Notification Retry Rules

When a webhook notification fails to deliver, the system will automatically retry based on the following rules.

#### Retry Schedule

Retries use an exponential backoff strategy. The delay between each retry attempt increases as follows:

<table data-search="false"><thead><tr><th>Attempt</th><th>Delay before retry</th></tr></thead><tbody><tr><td>1</td><td>Immediate</td></tr><tr><td>2</td><td>1 minute</td></tr><tr><td>3</td><td>2 minutes</td></tr><tr><td>4</td><td>5 minutes</td></tr><tr><td>5</td><td>10 minutes</td></tr><tr><td>6</td><td>15 minutes</td></tr><tr><td>7</td><td>30 minutes</td></tr><tr><td>8</td><td>1 hour</td></tr><tr><td>9</td><td>6 hours</td></tr><tr><td>10+</td><td>1 day</td></tr></tbody></table>

#### Maximum Attempts

The maximum number of retry attempts is controlled by the system setting `System.webhookAttempts`. This applies to all subscriptions, including those with "Do Not Unsubscribe" enabled. When the maximum is reached, the individual notification stops retrying, but the subscription remains active for new notifications.

#### Non-Retryable Errors

Notifications that fail with the following HTTP status codes are never retried, as these indicate permanent errors that will not resolve on their own:

<table data-search="false"><thead><tr><th>HTTP Status Code</th><th>Meaning</th></tr></thead><tbody><tr><td>400</td><td>Bad Request</td></tr><tr><td>401</td><td>Unauthorized</td></tr><tr><td>403</td><td>Forbidden</td></tr><tr><td>404</td><td>Not Found</td></tr><tr><td>405</td><td>Method Not Allowed</td></tr><tr><td>413</td><td>Payload Too Large</td></tr><tr><td>422</td><td>Unprocessable Entity</td></tr></tbody></table>

All other errors are retried, including:

* Connection timeouts (endpoint unreachable)
* Server errors (5xx)
* Rate limiting (429)
* Request timeouts (408)
* Conflicts (409)

#### Circuit Breaker

If a notification fails for a subscription during a retry cycle, all remaining pending notifications for that same subscription are skipped in that cycle. This prevents the system from repeatedly hitting a known failing endpoint. Skipped notifications are not counted as attempts — they will be picked up in the next cycle.

#### HTTP Timeouts

Webhook HTTP calls use configurable timeouts to prevent indefinite blocking:

| Setting    | Description                                              | Default    |
| ---------- | -------------------------------------------------------- | ---------- |
| `CTIMEOUT` | Connect timeout — maximum time to establish a connection | 15 seconds |
| `RTIMEOUT` | Read timeout — maximum time to wait for a response       | 60 seconds |

These can be configured via System Preferences.

#### Overlap Protection

If a retry cycle takes longer than the timer interval, the next cycle will not start until the current one finishes. This prevents multiple retry cycles from running simultaneously.

<br>


# Accounting Integration API

**The objective of** accounting integration is to *automate the creation and flow of transactions between the Dataloy VMS and an accounting system*. The advantage is, for example, reduced risk of errors as several transactions handled by the Dataloy VMS system generates transactions to be entered in a client accounting system. An integration also allows for synchronizing the basic data entities (or [*Master Data*](/api-release-8.26/dataloy-rest-api/master-data-objects)*, i.e. several of the same being stored and maintained in both systems*) between systems. Some Master Data, for example, Business Partners, must be synchronized for the integration to work.

## **Accounting Integration Transactions**

#### **Transactions from Dataloy VMS to Accounting:**

* Sales and purchase invoices are transferred whenever an invoice/invoices is/are posted in the VMS.
* Bunker transactions are transferred whenever a bunker transaction is posted in the VMS.
* Vessel/Voyage information is sometimes required by Accounting before invoices and/or bunker transactions are transferred. A scheduled task for transferring this type of information to Accounting can be set up.
* Accruals will be transferred by users when performing period-end-closing (*more information:* [*Accruals*](https://docs.dataloy.com/voyage-management-system/step-by-step-guides/finance/accruals) *page and the* [*Period-End-Closing*](https://docs.dataloy.com/voyage-management-system/step-by-step-guides/finance/accruals/period-end-closing) *process*).

#### **Transactions from Accounting to Dataloy VMS:**

* Receipts and payments being transferred from Accounting to Dataloy VMS. The transaction to collect and payments and send to the VMS is either triggered by Accounting or by a scheduled task (set up by Dataloy Systems).
* Exchange rates will be transferred from Accounting to Dataloy VMS. This transaction is either triggered by Accounting or by a scheduled task (set up by Dataloy Systems) to collect and retrieve the rates.
* Actuals is part of the [Period-End-Closing process](https://docs.dataloy.com/voyage-management-system/step-by-step-guides/finance/accruals/period-end-closing) and is usually transferred from Accounting to Dataloy VMS.


# Invoicing

## **Prerequisites**

Certain integrations need to be in place before the set-up and testing of an invoice integration:

* Transfer of voyage related data to the accounting system.
* Synchronization of business partners between Dataloy VMS and the accounting system.
* Exchange rate transfer to Dataloy VMS.
* Map accounts between Dataloy VMS and the accounting system.

## **Integration Set-Up**

When invoices are posted in Dataloy VMS, the document status is automatically set to Ready-for-Posting. Set up a webhook as described in the Data Transaction section below to extract invoices and credit notes that are ready for posting. When an invoice is transferred to accounting, update the status to Posted.

## **Dissolve or Reverse Invoice**

**To dissolve an assembled invoice** you need the document key and PUT as in the example below.

```
PUT /Document/{document key}
payload: {"invoicingStatus": "PEN"}
```

**To reverse a posted invoice** you need the document key and POST as in the example below.

```
POST /Document/{document key}/reverse
```

## Fetching invoice PDF

To fetch the PDF of a invoice, you will need the document key and perform a GET while having the field "invoice" as a part of the [fields-header](/api-release-8.26/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request#customize-the-number-of-fields-returned).

```
GET /Document/{document key}
fields: {"invoice": "*"}
```

{% hint style="warning" %}
The field "invoicePdf" is deprecated, and will not return any data.
{% endhint %}

{% hint style="info" %}
Only documents of type Invoice In, Invoice Out, Credit In, Credit Out and Advance Payment Req can be printed as PDF.
{% endhint %}

## **Data Transaction**

To get invoices that are ready for posting in [Webhooks](/api-release-8.26/dataloy-rest-api/webhooks) the following subscription can be created:

```
{
    "eventType":"U",
    "user": the user code to be used in the subscription,
    "objectType":"Document",
    "expression": "{"type":"group","id":"root","combine":"AND","items":[{"type":"condition","condition":{"id":"1782899454626-5vnfvqj","operator":"=","leftKind":"field","leftField":{"path":["invoicingStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"RFP"}},{"type":"group","id":"1782899467613-rlwidiv","combine":"OR","items":[{"type":"condition","condition":{"id":"1782899467613-0g14c7c","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"INO"}},{"type":"condition","condition":{"id":"1782899471039-tyeclsh","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"INI"}},{"type":"condition","condition":{"id":"1782899471428-5j3jh9q","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"CRI"}},{"type":"condition","condition":{"id":"1782899471816-cjdikzr","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"CRO"}}]}],"version":2}",
    "url": "your webhook url"
}
```

The expression logic if you want to use the expression builder: invoicingStatus.statusTypeCode = "RFP" AND (documentType.documentType = "INO" OR documentType.documentType = "INI" OR documentType.documentType = "CRI" OR documentType.documentType = "CRO")

Alternatively, a scheduled job can be set-up to use the following request:

### **Get invoices that are ready for posting to accounting**

| `GET /Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&filter=documentType.documentType(IN)(INI,INO,CRI,CRO)` |
| ------------------------------------------------------------------------------------------------------------------ |

### **Payment Terms**

There will be only one Document object in the API despite two payment terms for an invoice (for example 95/5 percent). However, the Document will have two documentPaymentTerms objects in the Document.documentPaymentTerms list.

To create two documents when integrating:

1. Loop on paymentTerms and create one document for each payment term.
2. Calculate the following values:
   * *dueDate*: document.documentPaymentTerms.dueDate
   * *documentAmount*: document.documentAmount \* document.documentPaymentTerms.percentage / 100
   * *companyCurrencyAmount*: document.companyCurrencyAmount \* document.documentPaymentTerms.percentage / 100
   * *sourceCurrencyAmount*: document.sourceCurrencyAmount \* document.documentPaymentTerms.percentage / 100

### **Test Data**

Test data for invoicing integration can be generated in the Dataloy VMS finance module (Accounts Receivable, Accounts Payable and Hire Payable).

### **Post Transaction**&#x20;

When an invoice is successfully transferred to an accounting system, the document status must be updated to *Posted* in Dataloy VMS. This is done in a PUT request:

```
PUT request on /Document/{key}
  
{
    "invoicingStatus": "POS"
}
```


# Payments/Receipts

## **Integration Set-Up**

When a payment is registered in the accounting system, it should be transferred as applicable to the *Posted* sections of either the Accounts Payable or the Accounts Receivable modules (where the matching invoice(s) can be found) in Dataloy VMS.

Since a payment in accounting systems may cover multiple Dataloy VMS payments/receipts, extracting payments from accounting means extracting invoices matching to a payment. Only payments/receipts records with a matching invoice in the applicable accounting system and with a required reference to a Dataloy invoice are to be extracted.

In Dataloy VMS all payments must match with the referenced invoice. To insert a payment/receipt in Dataloy VMS use the request under Data Transaction (below).

## **Data Transaction**

* A payment record should ONLY ever have one document line. Never more.

## **Amount Prefix**

This matrix is showing which prefix the payment amount should have for the various cases.

| <p><br></p>   | Accounts Payable and Hire Payable | Accounts Receivable |
| ------------- | --------------------------------- | ------------------- |
| Receipt (PMI) | Positive Amount                   | Negative amount     |
| Payment (PMO) | Negative Amount                   | Positive Amount     |

## **To Post a Payment/Receipt to Dataloy VMS:**

```
{
    "documentAmount": 10000.00,
    "companyCurrencyAmount": 10000.00,
    "sourceCurrencyAmount": 10000.00,
    "documentCurrency": "USD",
    "documentDate": "2014-01-01T00:00:00",
    "documentType": "PMO",
    "documentNo": "111111199",
    "externalDocumentNo": "50300",
    "company": "01",
    "businessPartner": "60526",
    "invoicingStatus": "POS",   
    "documentText": "text here",
    "documentLines":
    [
        {
            "documentAmount": 10000.00,
            "companyCurrencyAmount": 10000.00,
            "sourceCurrencyAmount": 10000.00,
            "documentCurrency": "USD",
            "invoicingStatus": "POS",
            "documentLineText": "text here",
            "businessPartner": "BPCODE",
            "isAccountsPayable": true,
            "refDocument": "71800125"
        }
    ]   
}
```


# Voyages

## **Prerequisites**

No prerequisites.

## **Integration Set-Up**

Accounting systems often require voyage related data before transferring accounting related transactions. Set up a scheduled task and use the request under [#data-transaction](#data-transaction "mention") to gather all voyages that has been modified since the last time a scheduled task was run.

## **Test Data**

Modify some existing voyages in the Booking and Operations module for testing, for example, changing a date in the schedule (***note**: changing dates will also affect the schedule for other voyages*).

## **Data Transaction**

### Get new voyages using webhooks

To get new voyages in [Webhooks](/api-release-8.26/dataloy-rest-api/webhooks) the following subscription can be created:

```
{
"eventType": "U",
"user":
"objectType": "VoyageHeader",
"expression": "{"type":"group","id":"root","combine":"OR","items":[{"type":"group","id":"1779183625231-nrms8uv","combine":"AND","items":[{"type":"condition","condition":{"id":"1779183625231-ctl7zhz","operator":"=","leftKind":"field","leftField":{"path":["voyageStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"previous","rightKind":"literal","rightValue":"EST"}},{"type":"condition","condition":{"id":"1779183710793-qsn8j3m","operator":"=","leftKind":"field","leftField":{"path":["voyageStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"NOM"}}]},{"type":"group","id":"1779183632027-tr8y79a","combine":"AND","items":[{"type":"condition","condition":{"id":"1779183632027-z9d3dbj","operator":"null","leftKind":"field","leftField":{"path":["referenceNo"],"type":"string","arrayFilters":[]},"leftSource":"previous","rightKind":"literal","rightValue":null}},{"type":"condition","condition":{"id":"1779183752798-06s1k61","operator":"notNull","leftKind":"field","leftField":{"path":["referenceNo"],"type":"string","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":null}},{"type":"condition","condition":{"id":"1779183769572-kl63bpk","operator":"=","leftKind":"field","leftField":{"path":["voyageStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"NOM"}}]}],"version":2}",
"url":
}
```

To get updated for all changes on a voyage the following webhook subscription can be created:

```
{
"eventType": "U",
"user":
"objectType": "VoyageHeader",
"url":
}
```

### **Get all fixed voyages modified since given date**

To extract all fixed voyages from Dataloy VMS that has been modified since a given date, use request below in conjunction with the base URL:

```
GET /VoyageHeader?filter=modifiedDate(GTE)2014-01-01T12:30:00
```

### **Post Transaction**&#x20;

No post transaction is required.


# Business Partners

## **Prerequisites**

Synchronization of business partners between Dataloy VMS and the applicable accounting system is required before transferring accounting related transactions. To synchronize business partner updates between systems, decide which system is to be the Master System (where the business partners will be updated). The Master System will then send updated business partner data to the other system.

## **Integration Set-Up**

* Dataloy VMS used as master:&#x20;
  * Dataloy recommends setting up up a [Webhook](/api-release-8.26/dataloy-rest-api/webhooks). As an alternative, setup a scheduled job and use the request under Data Transaction (below) to gather all business partners data having been modified since the last time a scheduled task was run.
* Dataloy VMS is *not* used as master: Use the requests under Data Transaction (below) to insert and update the business partners in Dataloy VMS.

## **Data Transaction**

### **Dataloy VMS as a master for business partners**

#### **Webhook**

Setup [Webhook subscriptions](/api-release-8.26/dataloy-rest-api/webhooks) for BusinessPartner, Address and ContactInfo. From Address and Contact info there is a reference back to the BusinessPartner key in the source field.

#### **Scheduled Job (If Webhook is not an option)**

Extract the business partners whose data has been modified since a selected date from Dataloy VMS using the following request in conjunction with the[ base URL](/api-release-8.26/dataloy-rest-api/getting-started):                                                                       &#x20;

#### **Get business partner information**

```
GET /BusinessPartner?filter=modifiedDate(GTE)2014-01-01T12:30:00
```

Set up a scheduled job and gather all voyages that have been modified since the last time a scheduled task was run.&#x20;

### **Other systems as Master for Business Partners**

Check if relevant business partner/s is/are already existing in Dataloy VMS by using the following request in conjunction with the base URL:                                                                                                   &#x20;

**Get business partner by key**

```
GET /BusinessPartner?filter=businessPartnerCode(EQ)99999
```

### If the business partner is already existing in Dataloy VMS

#### Update BusinessPartner

```
PUT /BusinessPartner
  
{
  "key": 1111111,
  "businessPartnerName": "Test Name",
  "businessPartnerCode": "123456789",
  "businessPartnerSort": "TESTNAME",
  "companyRegistrationNo": "123456789",
  "businessPartnerTypes": [
    {
      "businessPartnerType": "A"
    },
    {
      "businessPartnerType": "AU"
    }
  ],
  "bankAccounts": [
    {
      "key": 222222,
      "iban": "9754",
      "bankAccountNo": "6523",
      "bank": 1033615,
      "currency": 400132
    }
  ],
  "addresses": [
    {
      "key": 333333,
      "country": "NL",
      "address1": "Street Name 54",
      "address2": "5th floor",
      "address3": "",
      "city": "Amsterdam",
      "postalCode": "1000 AA"
    }
  ],
  "contactInfo": [
    {
      "key": 444444,
      "email": "test@test.com",
      "faxNo": "55555555",
      "mobileNo": "66666666",
      "phoneNo": "77777777",
      "telexNo": "88888888"
    }
  ]
}
```

### If the business partner does not exist in Dataloy VMS

[BusinessPartner API documentation](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/business-partner)

{% hint style="info" %}
***Note**: Use the Bank key if the Bank already exists. The below example is showing how to insert a new Bank when inserting a BusinessPartner*
{% endhint %}

```
POST /BusinessPartner

{
  "businessPartnerName": "Test Name",
  "businessPartnerCode": "123456789",
  "businessPartnerSort": "TESTNAME",
  "companyRegistrationNo": "123456789",
  "businessPartnerTypes": [
    {
      "businessPartnerType": "A"
    },
    {
      "businessPartnerType": "AU"
    }
  ],
  "bankAccounts": [
    {
      "iban": "9754",
      "bankAccountNo": "6523",
      "bank": {
        "bankName": "BP bank",
        "abaNumber": "1111",
        "chip": "2222",
        "swiftAddress": "42341"
      },
      "currency": 400132
    }
  ],
  "addresses": [
    {
      "country": "NL",
      "address1": "Street Name 54",
      "address2": "5th floor",
      "address3": "",
      "city": "Amsterdam",
      "postalCode": "1000 AA"
    }
  ],
  "contactInfo": [
    {
      "email": "test@test.com",
      "faxNo": "55555555",
      "mobileNo": "66666666",
      "phoneNo": "77777777",
      "telexNo": "88888888"
    }
  ]
}
```


# Exchange Rates

## P**rerequisites**

* An exchange rate source for extracting data to be inserted in Dataloy VMS.
* Base Currency must be set.\
  ***Note**: Locate Base Currency by getting ws/rest/System/1000000, then following relevant country link (Country Currency = the Base Currency).*

## **Integration Set-Up**

Set up a task for extracting exchange rates from either an accounting system or from a source delivering exchange rates service. Then insert the exchange rate into Dataloy VMS using the request under Data Transaction (below).

## **Data Transaction**

To insert an exchange rate in Dataloy VMS (fields required):

**Post an exchange rate to Dataloy**

```
POST /ExchangeRate
  
{
    "currency": "EUR",
    "fromCurrency": "USD",
    "exchangeRate": 0.74042,
    "exchangeRateDate": "2014-01-01T00:00:00"
}
```

### **Post Transaction**

No post transaction is required.


# Bunker Transactions

## **Prerequisites**

Before setting up and testing a bunker transaction integration other integrations need to be in place.

* [Transfer of voyage related data to the accounting system.](/api-release-8.26/user-guides/accounting-integration-api/voyages)
* [Synchronization of business partners between Dataloy VMS and the accounting system.](/api-release-8.26/user-guides/accounting-integration-api/business-partners)
* [Exchange rate transfer to Dataloy VMS.](/api-release-8.26/user-guides/accounting-integration-api/exchange-rates)

## **Integration Set-Up**

When a bunker transaction is posted in Dataloy VMS, the document status is set to Ready-for-Posting. Set up a scheduled task and use the request under Data Transaction to extract bunker transactions that are ready for posting. When a bunker transaction is transferred to accounting, update the status to Posted.

## **Test Data**

Test data for bunker transactions can be generated in Booking and Operations > Bunkers-FO tab > Bunker Transactions.

## **Data Transaction**

To get bunker transactions that are ready for posting in [Webhooks](/api-release-8.26/dataloy-rest-api/webhooks) the following subscription can be created:

```
{
    "eventType":"U",
    "user": the user code to be used in the subscription,
    "objectType":"Document",
    "expression": "{"type":"group","id":"root","combine":"AND","items":[{"type":"condition","condition":{"id":"1782903512505-wqx06zl","operator":"=","leftKind":"field","leftField":{"path":["invoicingStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"RFP"}},{"type":"condition","condition":{"id":"1782903524453-kmp0t03","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"ACC"}}],"version":2}",
    "url":"your webhook url"
}
```

If you use the expression builder, create an expression like this: invoicingStatus.statusTypeCode = "RFP" AND documentType.documentType = "ACC"

Alternatively a scheduled job can be setup to use the following request:

**Get bunker transactions that are ready for posting to accounting**

| `GET /Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&filter=documentType.documentType(EQ)ACC` |
| ---------------------------------------------------------------------------------------------------- |

### **Post Transaction**

When an invoice is successfully transferred to the accounting system, the document status has to be updated to *Posted* in Dataloy VMS. This is done in a PUT request:

**Update status to posted for a specific invoice**

```
PUT /Document/{key}
  
{
    "invoicingStatus": "POS"
}
```


# Actuals

## **Prerequisites**

[Invoice Integration ](/api-release-8.26/user-guides/accounting-integration-api/invoicing)needs to be in place before setting up and testing actuals integration.

## **Integration Set-Up**

Transfer of actuals (*or physicals*) from Accounting to Dataloy VMS can either be setup as a manual task through the Period-End-Closing Process or as a scheduled task. *Actuals* in accounting are actual costs and revenues, and once entered into Dataloy VMS, the actual record will appear in the Posted section of the Accruals module. Bunker transactions in Accounting that has been transferred from Dataloy VMS are not to be transferred, as they are already treated as actuals in Dataloy VMS (more information: actuals and accruals page and the Period-End-Closing process.

## **Data Transaction**

To insert an actual in Dataloy VMS:

* An actual record should ONLY ever have one document line. Never more.
* The document date should be the first day of the period month.
* Client can choose to insert actuals one by one or group actuals by period, currency, voyage, account and company
* Set a unique document number (*documentNo*).

Use request:

**Post an actual to Dataloy**

```
POST /Document
  
{
    "documentAmount": 10000.00,
    "companyCurrencyAmount": 10000.00,
    "sourceCurrencyAmount": 10000.00,
    "documentDate": "2014-01-01T00:00:00",
    "documentType": "ACC",
    "documentNo": "111111187",
    "company": "01",
    "invoicingStatus": "POS",
    "documentCurrency": "USD",
    "documentText": "text here",
    "glAccount": "1000",
    "documentLines":
    [
        {
            "documentAmount": 10000.00,
            "companyCurrencyAmount": 10000.00,
            "sourceCurrencyAmount": 10000.00,
            "documentCurrency": "USD",
            "exchangeRate": 1,
            "invoicingStatus": "POS",
            "documentLineText": "text here",
            "voyage": "VOY100",
            "glAccount": "1000"
        }
    ]
}
```

### Post Transaction

No post transaction is required.

<br>


# Autopost Invoices

When inserting data that in the end will result in an account payable, you might want to post the invoice directly. This can be done with a couple of API calls.

## Generate Invoice Lines

To generate invoice lines you need to know the key of the voyage that your data relates to. If you dont have the voyage key already you need to get it from the API either by getting it at an earlier stage in your integration or with a separate call in this stage. If you for instance already have the port call key you can get the voyage key by doing a GET request on PortCall.

To generate invoice lines post the below request, where key is the voyage key. For multiple voyages, add multiple keys.

```
POST /ws/rest/Document/refreshDocumentLines?key=123&key=456&isAccountsPayable=true
Body: empty

To locate the voyage key for Service Order and Bunker Order:

Service Order:
GET /ws/rest/ServiceOrder/{key}
Http header:
fields: {"portCall": {"voyage": {"key":"*"}}}

Bunker Order:
GET /ws/rest/BunkerOrder/{key}
Http header:
fields: {"portCall": {"voyage": {"key":"*"}}}
```

Then get the new invoice lines, called document lines in the API

```
Service Orders:
GET /ws/rest/DocumentLine?filter=voyage(IN)(123,456)&filter=document(NULL)
&filter=invoicingStatus.statusTypeCode(EQ)PEN&filter=portCall.key(EQ)118616134&filter=portCost.portAgent.daReference(EQ)DA-123

Bunker Orders:
GET /ws/rest/DocumentLine?filter=voyage(IN)(7173894)&filter=document(NULL)
&filter=invoicingStatus.statusTypeCode(EQ)PEN&filter=portCall.key(EQ)7173995
&filter=bunkerOrderLine.bunkerOrder.key(EQ)8366819
```

## Get invoice defaults (optional)

The below endpoint will give you data that can be used when assembling the invoice. Like bank account, issuing company and so on. If you already have the data you can skip this step.

```
POST /ws/rest/Document/invoiceDefaults

Header: disablebl = true (only for jvms customers)

Body:
{"documentLines":[{"key":111},{"key":222}], "invoicingStatus": "PEN"}
```

## Assemble invoice

Assemble the invoice with this request

```
POST /ws/rest/Document/assemble

Header: disablebl = true (only for jvms customers)

​​{
    "bankAccount": "bankAccountNo",
    "businessPartner": "businessPartnerCode",
    "documentCurrency": "USD",
    "documentDate": "2022-02-23T00:00:00",
    "documentLines": [{ "key": 111 }, { "key": 222 }],
    "documentPaymentTerms": [
        {
            "baselineDate": "2022-02-23T00:00:00",
            "baselineTerm": "baselineTermCode",
            "dueDate": "2022-03-02T00:00:00",
            "paymentTerms": "paymentTermsCode",
            "percentage": 100
        }
    ],
    "documentText": "A document text",
    "exchangeRate": 1,
    "exchangeRateDate": "2022-02-23T09:28:26",
    "externalDocumentNo": "1234",
    "issuingCompany": "companyCode",
    "invoicingStatus" : "INV"
}
```

* Mandatory fields: documentText, documentDate, issuingCompany, bankAccount, baseLineDate, baseLineTerms, dueDate, paymentTerms and percentage.
* If payment terms percentage is 100%, there should only be one entry in documentPaymentTerms
* BaseLineTerm is customer specific and needs to be agreed with customer. The baseline terms can be found at /ws/rest/BaselineTerm
* PaymentTerms is customer specific and needs to be agreed with customer. The payment terms can be found at /ws/rest/PaymentTerms

The request will return the new invoice, called Document in the API. Keep the Document key to post the document in next step.

## Post invoice

The final request will set the status to ready for posting which will cause accounting integrations to pick up the invoice and transfer it to accounting. The Document key is returned the assemble response in previous step.

```
PUT /ws/rest/Document/789

Header: disablebl = true (only for jvms customers)

{"invoicingStatus":"RFP"}
```


# Accruals

## **Prerequisites**

Before setting up and testing an invoice integration other integrations need to be in place:

* [Invoice Integration](/api-release-8.26/user-guides/accounting-integration-api/invoicing)
* [Actuals Integration](/api-release-8.26/user-guides/accounting-integration-api/actuals-1)

## **Integration Set-Up**

When accruals have been verified and posted in Dataloy VMS, the document status is set to *Ready-for-Posting*.

More information, go to Accruals and Period-End-Closing.

## **Data Transactions**

### **Get accruals and accrual reversals that are ready for posting to accounting**

To get accruals that are ready for posting in [Webhooks](/api-release-8.26/dataloy-rest-api/webhooks) the following subscription can be created:

```
{
    "eventType":"U",
    "user": the user code to be used in the subscription,
    "objectType":"Document",
    "expression": "{"type":"group","id":"root","combine":"AND","items":[{"type":"condition","condition":{"id":"1782903975402-box7vo7","operator":"=","leftKind":"field","leftField":{"path":["invoicingStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"RFP"}},{"type":"group","id":"1782903976004-c70ukle","combine":"OR","items":[{"type":"condition","condition":{"id":"1782903976004-ncwqszm","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"ACP"}},{"type":"condition","condition":{"id":"1782903996392-x0fuak4","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"ACR"}}]}],"version":2}",
    "url":"your webhook url"
}
```

If you use the expression builder, create an expression like this: invoicingStatus.statusTypeCode = "RFP" AND (documentType.documentType = "ACP" OR documentType.documentType = "ACR")

Alternativel&#x79;**,** a scheduled job can be setup to use the following request:

| `GET /Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&filter=documentType.documentType(IN)ACP,ACR,CAP,CAR` |
| ---------------------------------------------------------------------------------------------------------------- |

### **Test Data**

Test data for accruals integration can be generated in the Accruals module in Dataloy VMS. Generate and batch post the accruals.

### **Post Transaction** &#x20;

When an accrual is successfully transferred to an accounting system, the accrual status must to be updated to *Posted* in Dataloy VMS. This is done in a PUT request:&#x20;

**Update status to posted for a specific invoice**

```
PUT /Document/{key}
  
{
    "invoicingStatus": "POS"
}
```


# Additional information

## **List of Document Statuses in Dataloy VMS**

| Document Status Code | Document Status Description | Description                                                                                                                                                                                                  |
| -------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| PEN                  | Pending                     | <p>Invoice is in the Pending section of either Accounts Payable  (AP), Accounts Receivable (AR) or Hire Payable (HP)<br>in Dataloy VMS.</p>                                                                  |
| INV                  | Approval                    | <p>Invoice is in the Assembled section of either Accounts Payable  (AP), Accounts Receivable (AR) or Hire Payable (HP)<br>in Dataloy VMS.</p>                                                                |
| RFP                  | Ready-For-Posting           | <p>Invoice is in the Posted section section of either Accounts Payable  (AP), Accounts Receivable (AR) or Hire Payable (HP)<br>in Dataloy VMS, but has not yet been transferred to an accounting system.</p> |
| POS                  | Posted                      | <p>Invoice is in Posted section of either Accounts Payable  (AP), Accounts Receivable (AR) or Hire Payable (HP)<br>in Dataloy VMS and has been transferred to an accounting system.</p>                      |

## **List of Document Line Fields**

| Field Name                     | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Not possible to user in filters |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| documentAmount                 | <ul><li>For /DocumentTypes INO, INI, CRI, CRO: Amount in order currency/sales currency. The original currency.</li><li>For /DocumentTypes PMI, PMO: Amount in Invoice Currency.</li><li>For /DocumentTypes ACR, ACP: Amount in Voyage Currency.</li><li>For /DocumentTypes APR: Amount in Advance Currency</li><li>For /DocumentTypes ACC: Amount in Invoice Currency (use Voyage currency if Invoice Currency is not present)</li></ul>                                                                                                                                                                                                                   |                                 |
| companyCurrencyAmount          | For all /DocumentTypes : Amount in Company Currency for the Document.Company.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |                                 |
| sourceCurrencyAmount           | <ul><li>For /DocumentTypes INO, INI, CRI, CRO: Amount in order currency/sales currency. The original currency.</li><li>For /DocumentTypes PMI, PMO: Amount in Original Payment Currency.</li><li>For /DocumentTypes ACR, ACP: Amount in Voyage Currency.</li><li>For /DocumentTypes APR: Amount in Advance Currency</li><li>For /DocumentTypes ACC: Amount in Voyage Currency</li></ul>                                                                                                                                                                                                                                                                    |                                 |
| documentCurrency.currencyCode  | Currency Code for documentAmount. More information, see documentAmount                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |                                 |
| sourceCurrencyCode             | Currency code for sourceCurrencyAmount. More information see sourceCurrencyAmount                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |                                 |
| exchangeRate                   | Exchange Rate between documentAmount and sourceCurrencyAmount                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |                                 |
| exchangeRateDate               | Exchange Rate Date                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |                                 |
| glAccount                      | General Ledger Account                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | X                               |
| quantity                       | <p>Has Different Meaning Depending on Document Type:<br></p><ul><li>Accruals - <em>Onhire Days Within Accrual Period</em></li><li>Bunkers - <em>Bunker Quantity</em></li><li>Freight - <em>Cargo Quantity</em></li><li>Charter Hire - <em>Days</em></li><li>Meals and Cables - <em>Days</em></li><li>VAT - <em>VAT Amount is Quantity \* vatRate</em></li><li>Various, Days - <em>Voyage Days</em></li><li>Various, Rate - <em>Cargo Quantity</em></li><li>Offhire - <em>Offhire Days</em></li><li>Deadfreight - <em>Deadfreight Quantity</em></li><li>Demurrage/Despatch - <em>Days</em></li></ul>                                                        |                                 |
| unitPrice                      | Unit Price. Quantity \* Unit Price = Document Amount                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |                                 |
| invoicingStatus.statusTypeCode | Status Code, see [Document Status List](#list-of-document-statuses-in-dataloy-vms)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |                                 |
| documentLineText               | Document Line Text/Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |                                 |
| businessPartner                | <p>Business Partner Object. (Value: businessPartnerCode or businessPartner Key).</p><p>Invoice and Payment/Receipt:</p><ul><li><p>Outgoing invoice:</p><ul><li>document.company is the company in Dataloy VMS issuing the invoice.</li><li>document.businessPartner is the business partner receiving the invoice.</li><li>On the referring payment, document.company is receiving the payment.</li></ul></li><li><p>Incoming invoice:</p><ul><li>document.businessPartner is issuing the invoice.</li><li>document.company is receiving the invoice.</li><li>On the referring payment document.company is the one paying the invoice.</li></ul></li></ul> |                                 |
| isAccountsPayable              | <p>false = Accounts Receivable, true = Accounts Payable<br><br>Inserting Payment/Receipt:<br>For payments referring to Accounts Receivable invoices set value to 0. For payments referring to Accounts Payable invoice set value to 1. This value should always have the same value as for the referring invoice.</p>                                                                                                                                                                                                                                                                                                                                      |                                 |
| refDocument                    | <p>Referring Document for Reversals, Payments and Receipts. To set refDocument use Document Number or Key.</p><p>Payment/Receipts: Setting refDocument for payment receipts, documentLine.voyage will be set equal to the documentLine.voyage of the referring invoice.</p>                                                                                                                                                                                                                                                                                                                                                                                |                                 |
| vatRate.vatRate                | VAT Rate                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |                                 |
| vatRate.vat.vatCode            | VAT Code                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |                                 |
| freightRate                    | Freight Rate Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |                                 |
| portCall                       | portCall Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |                                 |
| handlingCost                   | handlingCost Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |                                 |
| businessUnit                   | businessUnit Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |                                 |
| account                        | Account Object, use glAccount instead                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |                                 |
| handlingCostCode               | handlingCostCode Object, use glAccount instead                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |                                 |
| billOfLading                   | billOfLading Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |                                 |
| claim                          | Claim Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |                                 |
| offhire                        | Offhire Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |                                 |
| voyage                         | Voyage Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |                                 |

## **Bank Fields List**

| Field Name                                                                                       | Description  | Required | Unique | Not Possible to Set in Filters |
| ------------------------------------------------------------------------------------------------ | ------------ | -------- | ------ | ------------------------------ |
| bankName                                                                                         | Bank Name    | Yes      |        |                                |
| swiftAddress                                                                                     | SWIFT Code   | Yes      | Yes    |                                |
| chip                                                                                             | Chip ID      |          |        |                                |
| abaNumber                                                                                        | ABA Code     |          |        |                                |
| [addresses](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/address)        | Address      |          |        | X                              |
| [contactInfo](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/contact-info) | Contact Info |          |        | X                              |


# Schedule API

Create a Voyage with a Loading and Discharging PortCall with one Cargo with a Loading and Discharging CargoPort.&#x20;

&#x20;

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre class="language-json"><code class="lang-json">POST /Voyage

{
"ballastPort":102546,
"vessel":1609791,
"cargos":\[
{
"cargoMeasurement":"MT",
"cargoType":"SPOT",
"cargoPorts":\[
{
"cargoPortSequence":1,
"port":105219,
"reasonForCall":"L"
},
{
"cargoPortSequence":1,
"port":101770,
"reasonForCall":"D"
}
]
}
],
"portCallsFromVoyage":\[
{
"port":105219,
"portCallSequence":1,
"reasonForCall":"L",
"currency":"EUR"
},
{
"port":101770,
"portCallSequence":2,
"reasonForCall":"D",
"currency":"EUR"
}
]
} </code></pre></td></tr></tbody></table>

The created voyage will get the status Estimated (code EST).

Creating a new Cargo with a Loading and Discharging CargoPort and PortCall. The PortCall objects have EventLogDates that specify Arrival, Berthing, Un-berthing, and Departure dates.

```json
POST /Cargo
 
{
    "cargoMeasurement": "MT",
    "cargoPorts": [
        {
            "cargoPortSequence": 1,
            "cargoQuantity": 1234,
            "laytimeTermsMeasurement": "H",
            "port": {
                "key": 102381
            },
            "portCall": {
                "portCallSequence": 3,
                "reasonForCall": "L",
                "port": 102381,
                "voyage": 6136896
            },
            "reasonForCall": "L"
        },
        {
            "cargoPortSequence": 1,
            "cargoQuantity": 1234,
            "freightRate": 1210,
            "laytimeTermsMeasurement": "H",
            "port": {
                "key": 101486
            },
            "portCall": {
                "portCallSequence": 4,
                "reasonForCall": "D",
                "port": 101486,
                "voyage": 6136896
            },
            "reasonForCall": "D"
        }
    ],
    "charterer": {
        "key": 1004307
    },
    "commodity": {
        "key": 1675975
    },
    "freightCurrency": "USD",
    "voyage": {
        "key": 6136896
    }
}
```

Adding to a Cargo a new Loading or Discharging CargoPort and PortCall

```json
PUT /Cargo/{KEY}
 
{
    "cargoPorts": [
        {
            "key": 18739785
        },
        {
            "key": 18739786
        },
        {
            "port": 103991,
            "reasonForCall": "D",
            "cargoPortSequence": 2,
            "portCall": {
                "portCallSequence": 6,
                "reasonForCall": "D",
                "port": 103991,
                "voyage": 18739534,
                "ownedByVoyage": 18739534
            }
        }
    ]
}

```

Fixing the date on an EventLog object. Note, only EventLogs with EventLog.EventLogDate from the past can be fixed, otherwise, the returned value of isDateFixed will be *false*.

```json
PUT /EventLog/{KEY}

{
    "isDateFixed":true
}
```

### Nominate an estimate voyage

To nominate a voyage of a given vessel first you need to get the last sequence for the vessel in the fleet plan:

```
GET https://dev.dataloy.com/ws/rest/Voyage?filter=vessel(EQ)1609791&fleetPlanVoyages.fleetPlan.fleetPlanCode(EQ)MASTER&filter=voyageHeader.voyageStatus.statusTypeCode(NE)EST&sort=fleetPlanVoyages.sequence(DS)
```

sending the HTTP Header property **fileds** withi this value:

`{"fleetPlanVoyages":{"sequence":"*"}}`

Then you can nominate the voyage making a PUT sending this payload:

```json
{
   "key":76409955,
   "voyageHeader":{
      "key":76409960,
      "voyageStatus":"NOM",
      "isVoyageStartFixed":false,
      "isEstimate":false,
      "isUnallocated":false
   },
   "fleetPlanVoyages":[
      {
         "fleetPlan":"MASTER",
         "voyage":76409955,
         "sequence":11,
         "vessel":1609791
      }
   ]
}
```

incrementing the sequence by 1.


# Bunker Order Integration API


# Service Order Integration API

**The objective of** the Service Order integration is to trigger the ordering of port related services and receive updates on estimated, revised and actual cost from parties handling the orders. The costs are internally assigned to the correct port call, vessel and voyage and processed further inside the VMS.

### Description

***Note**: Recommended before proceeding - read: Getting Started with Dataloy REST API.*

The endpoints for the Port Service Order process are:

1. [ServiceCode](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-code).
2. [ServiceOrder](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-order).
3. [ServiceOrderLine](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-order-line).

ServiceOrder objects are created by Dataloy VMS with the status Draft,  status code **DFT**.

The integration should use *Webhooks* to be notified when a new ServiceOrder object is created.

POST.WebhookSubscription:

```json
     {
        "user":  12345679,
        "channelInfo": {
            "url": "https://push.here.com",
            "channelType": "HTTP"
        },
        "eventType": "C",
        "objectType": "ServiceOrder"
    }
```

The JSON sent, when a service order is created, will have this structure:

```json
{
   "id":"0:ffff7f000001:-1c943d78:678f500d:42f06",
   "eventTime":"2025-01-22T07:41:46",
   "eventType":"C",
   "objectType":"ServiceOrder",
   "dataloyObject":69801182,
   "dataloyObjectSelf":"https://dev.dataloy.com/ws/rest/ServiceOrder/69801182",
   "subscription":{
      "key":69801122,
      "self":"https://dev.dataloy.com/ws/rest/WebhookSubscription/69801122"
   },
   "resource":{
      "key":69801182,
      "self":"https://dev.dataloy.com/ws/rest/ServiceOrder/69801182",
      "currency":{
         "key":400132,
         "self":"https://dev.dataloy.com/ws/rest/Currency/400132"
      },
      "status":{
         "key":51969046,
         "self":"https://dev.dataloy.com/ws/rest/StatusType/51969046"
      },
      "orderDate":"2024-05-18T20:22:00",
      "exchangeRate":1.0,
      "portAgentType":null,
      "portCall":{
         "key":69276170,
         "self":"https://dev.dataloy.com/ws/rest/PortCall/69276170"
      },
      "serviceOrderLines":[
         
      ],
      "amount":0.0,
      "amountAdvanced":0.0,
      "amountHandlingCost":0.0,
      "amountHandlingCostVoyageCurrency":0.0,
      "amountPortCost":0.0,
      "amountPortCostVoyageCurrency":0.0,
      "amountVariousCost":0.0,
      "amountVariousCostVoyageCurrency":0.0,
      "amountVoyageCurrency":0.0,
      "emailSentDate":null,
      "amountAdvancedCurrency":{
         "key":400132,
         "self":"https://dev.dataloy.com/ws/rest/Currency/400132"
      },
      "businessPartner":{
         "key":1318806,
         "self":"https://dev.dataloy.com/ws/rest/BusinessPartner/1318806"
      },
      "nominationEmail":null,
      "externalReferenceNo":"1737531705924",
      "createdById":66007605,
      "createdDate":"2025-01-22T07:41:45",
      "externalObjectKey":null,
      "modifiedDate":null,
      "changedById":66007605,
      "remarks":[
         
      ],
      "isObjectActive":true
   }
}
```

It is possible to be notified only by the raw object, in this case the WebhookSubscription has to have the following property:

```
"rawObject" : true
```

In this case the JSON sent will be like this:

```json
{
   "key":69801182,
   "self":"https://dev.dataloy.com/ws/rest/ServiceOrder/69801182",
   "currency":{
      "key":400132,
      "self":"https://dev.dataloy.com/ws/rest/Currency/400132"
   },
   "status":{
      "key":51969046,
      "self":"https://dev.dataloy.com/ws/rest/StatusType/51969046"
   },
   "orderDate":"2024-05-18T20:22:00",
   "exchangeRate":1.0,
   "portAgentType":null,
   "portCall":{
      "key":69276170,
      "self":"https://dev.dataloy.com/ws/rest/PortCall/69276170"
   },
   "serviceOrderLines":[
      
   ],
   "amount":0.0,
   "amountAdvanced":0.0,
   "amountHandlingCost":0.0,
   "amountHandlingCostVoyageCurrency":0.0,
   "amountPortCost":0.0,
   "amountPortCostVoyageCurrency":0.0,
   "amountVariousCost":0.0,
   "amountVariousCostVoyageCurrency":0.0,
   "amountVoyageCurrency":0.0,
   "emailSentDate":null,
   "amountAdvancedCurrency":{
      "key":400132,
      "self":"https://dev.dataloy.com/ws/rest/Currency/400132"
   },
   "businessPartner":{
      "key":1318806,
      "self":"https://dev.dataloy.com/ws/rest/BusinessPartner/1318806"
   },
   "nominationEmail":null,
   "externalReferenceNo":"1737531705924",
   "createdById":66007605,
   "createdDate":"2025-01-22T07:41:45",
   "externalObjectKey":null,
   "modifiedDate":null,
   "changedById":66007605,
   "remarks":[
      
   ],
   "isObjectActive":true
}
```

{% content-ref url="/pages/-MLgl845hNHAl9v20sym" %}
[Adjust Number of Fields to be Returned from a Request](/api-release-8.26/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request)
{% endcontent-ref %}

The ***fields*** property to customize the messages must be encoded with Base64 and set in attribute ***json*** of the WebhookSubscription

If the integration want to be notified also when there are changes to the PortCall connected with the ServiceOrder, a WebhookSubscription like this should be POST:

```json
     {
        "user":  12345679,
        "channelInfo": {
            "url": "https://push.here.com",
            "channelType": "HTTP"
        },
        "eventType": "U",
        "objectType": "PortCall",
        "dataloyObject": 36344213
    }
```

where “dataloyObject“: 3644213 is the PortCall key.

The integration can change an existing Service Order through HTTP PUT, see [ServiceOrder](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-order), [ServiceOrderLine](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-order-line).

To add a new line to a a order:

PUT:[https://url/ws/rest/ServiceOrder/](https://millenary-test.dataloy.com/ws/rest/ServiceOrder/33851810){ServiceOrder\_key}

```json
{
    "serviceOrderLines": [
        {
            "amountEstimate": 200,
            "description": "first line",
            "isCharterersCost": false,
            "isOwnersCost": false,
            "serviceCode": "PRC"
        }
    ]
}

```

**Auto Posting of Invoices**

Auto posting of service order invoices is supported for integrations with external agency systems. This feature allows invoices to be automatically posted when service orders are updated via the API.

A key prerequisite is configuring the [**Auto Post Service Order** system setting](https://docs.dataloy.com/voyage-management-system/step-by-step-guides/setup/system-settings/general). This setting determines the service order status from which auto posting is enabled and includes invoicing properties such as *Default Payment Term* and *Default Baseline Term*.

Once configured, it's essential to include the `autoPost = true` HTTP header in all PUT requests to service orders and/or service order lines. This will trigger the automatic posting of the invoices based on the updated data.

**Important Note**

* **Manual Changes Will Not Trigger Auto Posting**
  * Changes made via the VMS client UI (manually by users) will NOT trigger auto posting. This feature is exclusive to API-based integrations.

{% code overflow="wrap" %}

```
PUT /ws/rest/ServiceOrder/6420123 HTTP/1.1
Host: localhost:8080
autoPost: true
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkVJWjlvcFlVZWZaLXVsbTk5SUpCTyJ9.eyJpc3MiOiJodHRwczovL2ludGVybmFsLmV1LmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw2NGY5ODE4MzU5OGI3YTg2ZjllZDUzMTAiLCJhdWQiOlsiaHR0cHM6Ly9kYXRhbG95LmludGVybmFsIiwiaHR0cHM6Ly9pbnRlcm5hbC5ldS5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNzEyMDU2MjIwLCJleHAiOjE3MTIwNjM0MjAsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJhenAiOiJadGZXVTdYZEJmaGtQb0pSNHhCelVGQlpKU1htbzlJdCJ9.ZU
Content-Length: 190

{"serviceOrderLines":[{"key":6420124,"amountEstimate":12501,"amountFinal":0,
"amountRevised":0,"description":null,"isCharterersCost":true,
"isOwnersCost":false,"serviceCode":{"key":6003979}}]}
```

{% endcode %}

**Service Order statues**

* Draft, DFT
* Estimated, EST
* Revised, REV
* Final, FIN
* Cancel, CAN

**Service Order status transitions**&#x20;

<figure><img src="/files/2GBlhN39ZakjW0A6azNa" alt=""><figcaption></figcaption></figure>

**Service Order status transitions when Agent nomination is enabled**&#x20;

<figure><img src="/files/SLQlC9942BDTVMWeN1AY" alt=""><figcaption></figcaption></figure>


# Vessel Report


# Overview

PositionReport is used to update the status of an ongoing voyage's port calls.

## Overview

Position reports update a port call's sailing, arrival, in port, and departure status. Most fields in the PositionReport object will only provide information, while a few affect the port call's results.

The following fields will affect the port call's results:

* eventLogs
  * An [**EventLog**](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log) captures port events along with their dates and times. The port events include ARRIVAL, BERTHED, UNBERTHED, and DEPARTURE. To record the arrival date of a port call, an event log entry should include the ARRIVAL event along with the corresponding date.

  * A [**PositionReportBunker**](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker) records the remaining bunkers on board for a specific bunker category.

    <br>

Fields impacting the port call's results will have **Major Change Factor** marked as yes, along with a description, on the [details](#details).

PositionReport can be one of these types:

* Noon Report
  * logs the ship's status at sea, updating the estimated arrival date and ROB info
* Arrival Report
  * logs when the ship arrives in the port, fixing the arrival date and ROB info
* Berth Report
  * logs when the ship has berthed in the port, fixing the berthed date and ROB info
* Unberth Report
  * logs when the ship has unberthed in the port, fixing the unberthed date and ROB info
* In Port Report
  * logs supplementary information such as hours in service, weather, wind direction and average wind direction when the ship is docked.&#x20;
* Departure Report
  * logs when the ship leaves the port, fixing the departure date and ROB info

In order to include a [Remark](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/remark) on the position report, a separate API request must be made after the report is created. See [here](#arrival-report-with-remark) for an example.

## Details

### Noon Report&#x20;

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="215">Json Attribute</th><th width="161">Description</th><th>Mandatory</th><th>Major Change Factor</th><th width="209">Data type</th><th>Notes</th></tr></thead><tbody><tr><td>Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"NOON"</td></tr><tr><td>Noon Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td>yes</td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Latitude</td><td><code>latitude</code></td><td>Current position</td><td>yes</td><td></td><td>Double</td><td></td></tr><tr><td>Longitude</td><td><code>longitude</code></td><td>Current position</td><td>yes</td><td></td><td>Double</td><td></td></tr><tr><td>Estimated Time of Arrival</td><td><code>eventLogs</code></td><td>Date and time of estimated time of arrival</td><td>yes</td><td>yes, updates PortCall's arrival date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's arrival event log</p><p><br>date should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":100}]</code></td><td>Remaining bunkers on board at the time of reporting for the given bunker category</td><td></td><td>yes, updates PortCall's arrival rob</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td>one PositionReportBunker object for each bunker category</td></tr><tr><td>Wind Direction</td><td><code>windDirection</code></td><td>Determines current wind direction</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/direction">Direction</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#direction-data">Click here for more details</a></td></tr><tr><td>Average Wind Force</td><td><code>averageWindForce</code></td><td>General wind conditions</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Sea Direction</td><td><code>seaDirection</code></td><td>Current sea direction</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/direction">Direction</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#direction-data">Click here for more details</a></td></tr><tr><td>Average Sea State</td><td><code>averageSeaState</code></td><td>General sea conditions</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Weather</td><td><code>weather</code></td><td>Determines current weather</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/weather">Weather</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#weather-data">Click here for more details</a></td></tr><tr><td>Distance Sailed</td><td><code>distanceSailed</code></td><td>Distance sailed</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Hours in Service</td><td><code>hoursInService</code></td><td>Number of hours in operation</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Main Engine RPM</td><td><code>rpmFromLastPort</code></td><td>RPM recorded from previous port</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Noon report example

<details>

<summary>Noon Report sailing to a port</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query and headers:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

An example of the response could be found [here](#portcall-query-with-eventlogs-fields-response)

2. Generate a Noon Report for the vessel that has sailed 3150 nm to the queried PortCall, with South/West wind direction and partly cloudy weather.  Arrival LS MGO robs are also updated to 250

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

{% code overflow="wrap" %}

```json
{
    "vesselReportType": "NOON",
    "reportDateLocal": "2024-08-01T19:00:00",
    "portCall": 123456, //key from the response of the PortCall query
    "latitude": 60.2139,
    "longitude": 4.5300,
    "eventLogs": [
        {
            "key": 123456, //arrival event log key
            "eventLogDate": "2024-08-02T02:36:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 555
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 7777
        
        }
    ],
    "windDirection": 911643,
    "weather": 950928,
    "distanceSailed": 3150.00
}
```

{% endcode %}

</details>

### Arrival Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="198">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"ARR"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Arrival Date</td><td><code>eventLogs</code></td><td>Date and time of arrival on port</td><td>yes</td><td>yes, updates and fixes PortCall's arrival date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's arrival event log</p><p><br>date should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Arrival Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Actual Distance Sailed Since Departure</td><td><code>distanceSailed</code></td><td>Distance in nm sailed from previous port</td><td></td><td>yes, updates the PortCall's actual distance sailed</td><td>Double</td><td></td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":98}]</code></td><td>Remaining bunkers at the time of arrival for the given bunker category</td><td></td><td>yes, updates and fixes PortCall's arrival ROB</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td>one PositionReportBunker object for each bunker category</td></tr><tr><td>Hours Stoppage</td><td><code>hoursStoppages</code></td><td>Number of hours in stoppage of operation</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Hours In Service</td><td><code>hoursInService</code></td><td>Number of hours in operation</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Speed Made Good</td><td><code>speedMadeGood</code></td><td>Net speed when sailing to the port</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Draft Aft</td><td><code>draftAft</code></td><td>Vessel's draft aft</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Draft Forward</td><td><code>draftForward</code></td><td>Vessel's draft forward</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Arrival report example

<details>

<summary>Arrival report on port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

Example of the response can be found [here](#portcall-query-with-eventlogs-fields-response)

2. Generate a report for arrival at 2nd August 2024 03:00 with arrival FO ROB at 225.85 mt and arrival LS MGO ROB at 235 mt

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "ARR",
    "reportDateLocal": "2024-08-01T19:00:00",
    "portCall": 123456, //key from the response of the PortCall query
    "latitude": 60.2139,
    "longitude": 4.5300,
    "eventLogs": [
        {
           "key": 123456, //arrival event log key
            "eventLogDate": "2024-08-02T03:00:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 235
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 225.85
        
        }
    ]
}
```

</details>

### Berth Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="214">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"BRT"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Berth date</td><td><code>eventLogs</code></td><td>Date and time of berthing on port</td><td>yes</td><td>yes, updates and fixes PortCall's berthed date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's berth event log</p><p><br>date should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Berth Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":95}]</code></td><td>Remaining bunkers at the time of berthing for the given bunker category</td><td></td><td>yes, updates and fixes PortCall's berthing ROB</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td><p>one PositionReportBunker object for each bunker category</p><h4 id="berth-report-example"><br></h4></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Berth report example

<details>

<summary>Berth report on a port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

2. Generate a report that has berthed 3rd August 2024 08:00 with berth FO rob at 225 mt and DL rob at 220 mt

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "BRT",
    "reportDateLocal": "2024-08-03T10:36:00",
    "portCall": 123456, //key from the response of the PortCall query
    "eventLogs": [
        {
            "key": 123456, //berth event log key
            "eventLogDate": "2024-08-03T10:36:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 220
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 225
        
        }
    ]
}
```

</details>

### Unberth Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="207">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"UBRT"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Unberth date</td><td><code>eventLogs</code></td><td>Date and time of berthing on port</td><td>yes</td><td>yes, updates and fixes PortCall's berthed date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's unberth event log</p><p><br>date should be in this format: "YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Unberth Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":95}]</code></td><td>Remaining bunkers at the time of unberthing for the given bunker category</td><td></td><td>yes, updates and fixes PortCall's unberthing ROB</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td><p>one PositionReportBunker object for each bunker category</p><h4 id="berth-report-example"><br></h4></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Unberth report example

<details>

<summary>Unberth report on a port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

Example response can be found [here](#portcall-query-with-eventlogs-fields-response)

2. Generate a report that has unberthed 5th August 2024 08:00, FO unberth ROB at 225 mt, DL unberth at 218.5 mt

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "UBRT",
    "reportDateLocal": "2024-08-05T08:00:00",
    "portCall": 123456, //key from the response of the PortCall query
    "eventLogs": [
        {
            "key": 123456, //unberth event log key
            "eventLogDate": "2024-08-05T08:00:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 218.5
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 225
        
        }
    ]
}
```

</details>

### In Port Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="198">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"PORT"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>In Port Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Hours In Service</td><td><code>hoursInService</code></td><td>Number of hours in operation</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Weather</td><td><code>weather</code></td><td>Current weather</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/weather">Weather</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#weather-data">Click here for more details</a></td></tr><tr><td>Wind Direction</td><td><code>windDirection</code></td><td>Current wind direction</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/direction">Direction</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#direction-data">Click here for more details</a></td></tr><tr><td>Average Wind Force</td><td><code>averageWindForce</code></td><td>General wind conditions</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### In port report example

<details>

<summary>In port report on a port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

2. Generate a report to log sunny weather, East wind direction, hours in service, average wind force status in port

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "PORT",
    "reportDateLocal": "2024-08-03T18:00:00",
    "portCall": 123456, //key from the response of the PortCall request
    "hoursInService": 225.85,
    "weather": 950927,
    "windDirection": 911638,
    "averageWindForce": 1
}
```

</details>

### Departure Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="199">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"DEP"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Departure date</td><td><code>eventLogs</code></td><td>Date and time of departure from port</td><td>yes</td><td>yes, updates and fixes PortCall's departure date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's departure event log</p><p><br>date should be in this format: "YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Departure Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":90}]</code></td><td>Remaining bunkers at the time of departure for the given bunker category</td><td></td><td>yes, updates and fixes PortCall's departure ROB</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td>one PositionReportBunker object for each bunker category</td></tr><tr><td>Distance to next port</td><td><code>distanceToNextPort</code></td><td>Distance in nm to next port</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Draft Aft</td><td><code>draftAft</code></td><td>Vessel's draft aft</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Draft Forward</td><td><code>draftForward</code></td><td>Vessel's draft forward</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Departure Report example

<details>

<summary>Departure report on a port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

Example of the response can be found [here](#portcall-query-with-eventlogs-fields-response)

2. Generate a report that has fixes the departure date to  5th August 2024 08:30, departure FO rob at 225 mt and departure DL rob at 215 mt

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "DEP",
    "reportDateLocal": "2024-08-05T08:30:00",
    "portCall": 123456, //key from the response of the PortCall query
    "eventLogs": [
        {
            "key": 123456, //departure event log key
            "eventLogDate": "2024-08-05T08:30:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 218.5
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 225
        }
      ]
}
```

</details>

### More examples

<details>

<summary>PortCall query with "eventLogs" fields  response</summary>

```json
[
    {
        "key": 6130402,
        "eventLogs": [
            {
                "key": 6130391,
                "event": {
                    "key": 1000051,
                    "eventCode": "BRT"
                },
                "robs": [
                    {
                        "key": 6130447,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130450,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130462,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130464,
                        "rob": 249.75,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    }
                ]
            },
            {
                "key": 6130396,
                "event": {
                    "key": 6088041,
                    "eventCode": "UBRT"
                },
                "robs": [
                    {
                        "key": 6130444,
                        "rob": 249.75,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130452,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130459,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130470,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    }
                ]
            },
            {
                "key": 6130392,
                "event": {
                    "key": 1000052,
                    "eventCode": "DEP"
                },
                "robs": [
                    {
                        "key": 6130440,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130448,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130454,
                        "rob": 249.75,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130458,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    }
                ]
            },
            {
                "key": 6130395,
                "event": {
                    "key": 1000050,
                    "eventCode": "ARR"
                },
                "robs": [
                    {
                        "key": 6130451,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130460,
                        "rob": 250.0,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130467,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130469,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    }
                ]
            }
        ]
    },
    {
        "key": 6130400,
        "eventLogs": [
            {
                "key": 6130394,
                "event": {
                    "key": 1000051,
                    "eventCode": "BRT"
                },
                "robs": [
                    {
                        "key": 6130441,
                        "rob": 230.53559444257462,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130457,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130461,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130468,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    }
                ]
            },
            {
                "key": 6130398,
                "event": {
                    "key": 1000050,
                    "eventCode": "ARR"
                },
                "robs": [
                    {
                        "key": 6130445,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130456,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130463,
                        "rob": 230.78559444257462,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130471,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    }
                ]
            },
            {
                "key": 6130393,
                "event": {
                    "key": 6088041,
                    "eventCode": "UBRT"
                },
                "robs": [
                    {
                        "key": 6130442,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130443,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130453,
                        "rob": 230.53559444257462,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130466,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    }
                ]
            },
            {
                "key": 6130397,
                "event": {
                    "key": 1000052,
                    "eventCode": "DEP"
                },
                "robs": [
                    {
                        "key": 6130446,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130449,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130455,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130465,
                        "rob": 230.53559444257462,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    }
                ]
            }
        ]
    }
]
```

</details>

<details>

<summary>Arrival report with Remark</summary>

1. Send first this request

Example: Arrival vessel report to register arrival date at 8th August 2024 02:58, with remaining 98 MT of FO on board

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "ARR",
    "reportDateLocal": "2024-08-02T02:58:00",
    "portCall": 6130402, //key from the response of the PortCall request
    "eventLogs": [
        {
            "key": 6130395, //key of the arrival event log from the response of the PortCall request
            "eventLogDate": "2024-08-02T02:58:00"
        }],
      "positionReportBunkers": [
        {
            "bunkerCategory": "FO", 
            "rob": 98
        }]
}
```

2. The response of the query above returns the PositionReport key. Generate a Remark on the arrival position report that says "Arrival on the port remark":

```
POST /ws/rest/Remark HTTP/1.1
```

```
{
    source: 5535223, //key from the response of PositionReport request
    "remark": "Arrival on the port remark"
}
```

</details>

<details>

<summary>Arrival report where port call key and voyage key are not known, using voyage.referenceNo and port name</summary>

1. Fetch the port call key

{% code fullWidth="true" %}

```
GET /ws/rest/PortCall?filter=voyage.voyageHeader.referenceNo(LKIC)TST001&port.portName(LKIC)Bergen case insensitive HTTP/1.1
Authorization: Bearer ....
```

{% endcode %}

2. Generate arrival report

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "ARR",
    "reportDateLocal": "2024-08-02T02:58:00",
    "portCall": 6130402, //key from the response of the PortCall request
    "eventLogs": [
        {
            "key": 6130395, //key of the arrival event log from the response of the PortCall request
            "eventLogDate": "2024-08-02T02:58:00"
        }],
      "positionReportBunkers": [
        {
            "bunkerCategory": "FO", 
            "rob": 98
        }]
}
```

</details>


# Legacy version (6.26 - 6.28)

**Dataloy Vessel Report System** enables vessels to send vessel reports *without proper internet connection*. The server side of Dataloy VRS is exposed in the Dataloy API for inserting vessel reports into Dataloy VMS. When Dataloy VRS is in use, the client side of the Vessel Report API system can be ignored - the message sent by e-mail to the VRS is identical to what can be posted in the Vessel Report API (with minor adjustments). Inserting a vessel report into Dataloy VMS *not only* inserts a position report, but also the schedule, bunkers etc. There is also a functionality available for locating correct port call based on vessel code and report date.

Chapter Contents:&#x20;

* [Vessel Report API Process](#vessel-report-api-process)
* [Alerts](#alerts)
* [Noon report](#noon-report)
* [Arrival report](#arrival-report)
* [In Port Report](#in-port-report)
* [Departure Report](#departure-report)
* [Example Messages](#example-messages)
* [Consumption Breakdown](#consumption-breakdown)
* [Weather Data](#weather-data)
* [Direction](#direction)
* [Reason For Call](#direction)
* [Dataloy Vessel Code](#dataloy-vessel-code)
* [Dataloy Port ID](#dataloy-port-id)

### **Vessel Report API Process**

**Base URL**

The Vessel Report URL:

| `Base URL + ws/rest/VesselReport` |
| --------------------------------- |

**Custom Fields**

Custom fields can be added

* using Events (if there is an event code and date).
* or added as a Remark (text field).

Events are added and retrieved from [Master Data](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F6.46/master-data) and can be used in a JSON message. Event fields in the JSON message is shortened:

* ed = event date
* ec = event code.

Remarks will be connected to the Position Report. To send remarks requires:

* the set-up of a remark template in the database with a title and the extraction of the remark\_id.\
  ***Note**: This construction is usually met with various various challenges with e-mail based vessel reporting (more information:* [***contact Dataloy***](http://support.dataloy.com/)*).*

**IMPORTANT**: This type of construction causes various challenges with e-mail based vessel reporting (*more information: contact* [***contact Dataloy***](http://support.dataloy.com/)).

### **Alerts**

Alerts can be triggered either:

* when reports are inserted to Dataloy VMS
* or a report is failing.

**IMPORTANT**: Property Settings is handled in: *Master Data > Dataloy Properties*.

\
**Properties**

| Property                                                | Description                                                                                                                                                                                                                                                       |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| com.dataloy.integration.vessel.voyageNoAndRFC           | When set to **true**: referenceNo and reasonForCall can be added to the json message. This makes it easier for VRS to locate the correct port call and will reduce errors.                                                                                        |
| com.dataloy.integration.vessel.reportMailRecipients     | <p>List of email addresses separated by semicolon.</p><p>A vessel report successfully inserted into Dataloy VMS results in a report being sent to the addresses in this property value. The report will list all values sent from the vessel.</p>                 |
| com.dataloy.integration.vessel.errormail.recipient      | <ul><li>E-mail address list separated by semicolon.</li><li>The e-mail address owners will receive an e-mail if a vessel report is failing.</li><li>The Voyage Operator will also receive a message if the User has registered relevant e-mail address.</li></ul> |
| com.dataloy.integration.vessel.errormail.sender         | An e-mail address will be the sender of the Error Mail.                                                                                                                                                                                                           |
| com.dataloy.integration.vessel.sendReportMailToOperator | When set to true: A vessel report successfully inserted into Dataloy VMS results in a report being sent to the Voyage Operator, listing all values sent from the vessel.                                                                                          |
| com.dataloy.mail.smtp                                   | *smtp* must be setup for e-mail alerts to function.                                                                                                                                                                                                               |

### **Noon report**<br>

<table data-header-hidden><thead><tr><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>JSON Field Name</td><td>Description</td><td>Affects Dataloy VMS</td><td>Mandatory</td><td>Type</td><td>Length</td></tr><tr><td>portCallId</td><td>A port call id</td><td>If the port call id is available, use this to avoid VRS trying to locate the correct port call.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>referenceNo</td><td>Voyage reference number</td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>reasonForCall</td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>.</td><td><br></td><td><br></td><td><br></td></tr><tr><td><pre><code>reportTypeCode
</code></pre></td><td><ul><li>Vessel Report Type</li><li>Value = NOON for Noon Report</li></ul></td><td>Used to insert correct type of Position Report and to locate correct port call.</td><td>Yes</td><td>String</td><td>4</td></tr><tr><td><pre><code>vesselCode
</code></pre></td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Used in combination with report date local time to locate the port call in Dataloy VMS.</td><td>Yes</td><td>String</td><td>6</td></tr><tr><td><pre><code>reportDateLocal
</code></pre></td><td>Report Date Local Time</td><td>Used in combination with vessel code to locate the port call in Dataloy VMS. Inserted in the Postition Report.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>latitude
</code></pre></td><td>Position Latitude (Decimal Degrees)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td>5</td></tr><tr><td><pre><code>longitude
</code></pre></td><td>Position Longitude (Decimal Degress)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td>5</td></tr><tr><td><pre><code>portId
</code></pre></td><td>Arrival Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an error message will be returned and the report will not be inserted.</td><td>Yes</td><td>Integer</td><td>38</td></tr><tr><td><pre><code>arrival
</code></pre></td><td>Estimated Time of Arrival</td><td>Updates ETA in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>berthed
</code></pre></td><td>Estimated Time of Berthing</td><td>Updates ETB in Schedule.</td><td><br></td><td>Date</td><td><br></td></tr><tr><td><pre><code>departure
</code></pre></td><td>Estimated Time of Departure</td><td>Updates ETD in Schedule.</td><td><br></td><td>Date</td><td><br></td></tr><tr><td><pre><code>trueCourse
</code></pre></td><td>True Course</td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>distanceSailed
</code></pre></td><td>Distance Sailed Since Last Report</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>hoursInService
</code></pre></td><td>Hours in Service Since Last Report</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>distanceToNextPort
</code></pre></td><td>Distance To Go</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>speedMadeGood
</code></pre></td><td>Speed Made Good</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>windDirectionId
</code></pre></td><td>Wind Direction (<a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>)</td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>averageWindForce
</code></pre></td><td>Wind Force. Beaufort.</td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>seaDirectionId
</code></pre></td><td>Sea Direction (<a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>)<br></td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>averageSeaState
</code></pre></td><td>Sea State. Integer from 0 - 9.</td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>bhpMainEngineIndicatedRpm
</code></pre></td><td>Main Engine RPM Since Last Report</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFo
</code></pre></td><td>Daily Fuel Oil Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyDo
</code></pre></td><td>Daily Diesel Oil Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFl
</code></pre></td><td>Daily Fuel Oil Low Sulphur Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyDl
</code></pre></td><td>Daily Diesel Oil Low Sulphur Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFw
</code></pre></td><td>Daily Net Fresh Water Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFo
</code></pre></td><td>Fuel Oil Remaining on Board (FO RoB)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDo
</code></pre></td><td>Diesel Oil Remaining on Board (DO RoB)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFl
</code></pre></td><td>Fuel Oil Low Sulphur Remaining on Board (FO LS RoB)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDl
</code></pre></td><td>Diesel Oil Low Sulphur Remaining on Board (DO LS RoB)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFw
</code></pre></td><td>Fresh Water Remaining on Board</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>genericRemark
</code></pre></td><td>Remark</td><td>Inserted as a Remark to the Position Report.</td><td><br></td><td>String</td><td>Unlimited</td></tr></tbody></table>

### **Arrival report** <br>

<table data-header-hidden><thead><tr><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>JSON Field Name</td><td>Description</td><td>Affets Dataloy VMS</td><td>Mandatory</td><td>Type</td><td>Length</td></tr><tr><td>portCallId</td><td>A port call id</td><td>If the port call id is available, use this to avoid VRS trying to locate the correct port call.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>referenceNo</td><td>Voyage reference number</td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td>reasonForCall</td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>  </td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td><pre><code>reportTypeCode
</code></pre></td><td>Vessel Report Type<br>Value = ARR for Arrival Report.</td><td>Used to insert the correct type of Position Report and to locate the correct port call. </td><td>Yes</td><td>String</td><td>4</td></tr><tr><td><pre><code>vesselCode
</code></pre></td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Used in combination with report date local time to locate the port call in Dataloy VMS.</td><td>Yes</td><td>String</td><td>6</td></tr><tr><td><pre><code>portId
</code></pre></td><td>Arrival Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an error message will be returned and the report will not be inserted.</td><td>Yes</td><td>Integer</td><td>38</td></tr><tr><td><pre><code>reportDateLocal
</code></pre></td><td>Report Date Local Time</td><td>Used in combination with vessel code to locate the port call in Dataloy VMS.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>arrival
</code></pre></td><td>Time of Arrival</td><td>Updates ETA in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>berthed
</code></pre></td><td>Time of Berthing (Estimated if Anchoring)</td><td>Updates ETB in Schedule</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>departure
</code></pre></td><td>Estimated Time of Departure</td><td>Updates ETD in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>distanceSailedSinceDeparture
</code></pre></td><td>Total Distance Sailed Since Departure</td><td>Updates Miles in Schedule.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>distanceSailed
</code></pre></td><td>Distance Sailed Since Last Report</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>hoursStoppages
</code></pre></td><td>Hours Stoppages</td><td>Updates Days Stoppages (<em>see the Perfomance tab in Booking and Operations</em>).</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>hoursInService
</code></pre></td><td>Hours in Service</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>speedMadeGood
</code></pre></td><td>Speed Made Good Since Last Report</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>draftAft
</code></pre></td><td>Draft Aft</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>draftForward
</code></pre></td><td>Draft Forward</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFo
</code></pre></td><td>Daily Fuel Oil Consumption<br></td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyDo
</code></pre></td><td>Daily Diesel Oil Consumption</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFl
</code></pre></td><td>Daily Fuel Oil Low Sulphur Consumption</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyDl
</code></pre></td><td>Daily Diesel Oil Low Sulphur Consumption</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFw
</code></pre></td><td>Daily Net Fresh Water consumption</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFo
</code></pre></td><td>Fuel Oil Remaining on Board (FO RoB)</td><td>Updates Fuel Oil Remaining on Board (FO RoB) Arrival.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDo
</code></pre></td><td>Diesel Oil Remaining on Board (DO RoB)</td><td>Updates Diesel Oil Remaining on Board (DO RoB) Arrival.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFl
</code></pre></td><td>Fuel Oil Low Sulphur Remaining on Board (FO LS RoB)</td><td>Updates Fuel Oil Low Sulphur Remaining on Board (FO LS RoB) Arrival.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDl
</code></pre></td><td>Diesel Oil Low Sulphur Remaining on Board (DO LS RoB)</td><td>Updates Diesel Oil Low Sulphur Remaining on Board (DO LS RoB) Arrival.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFw
</code></pre></td><td>Fresh Water remaining on board</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>genericRemark
</code></pre></td><td>Remark</td><td>Inserted as a Remark to the Position Report.</td><td><br></td><td>String</td><td>Unlimited</td></tr></tbody></table>

### **In Port Report**<br>

<table data-header-hidden><thead><tr><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>JSON Field Name</td><td>Description</td><td>Affects Dataloy VMS</td><td>Mandatory</td><td>Type</td><td>Length</td></tr><tr><td>portCallId</td><td>A port call id</td><td>If the port call id is available, use this to avoid VRS trying to locate the correct port call.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>referenceNo</td><td>Voyage reference number</td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td>reasonForCall</td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>  </td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td><pre><code>reportTypeCode
</code></pre></td><td>Vessel Report Type<br>Value = PORT for In Port Report.</td><td>Used to insert the correct type of Position Report and to locate the correct port call.</td><td>Yes</td><td>String</td><td>4</td></tr><tr><td><pre><code>vesselCode
</code></pre></td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Used in combination with report date local time to locate the port call in Dataloy VMS.</td><td>Yes</td><td>String</td><td>6</td></tr><tr><td><pre><code>portId
</code></pre></td><td>Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an error message will be returned and the report will not be inserted.</td><td>Yes</td><td>Integer</td><td>38</td></tr><tr><td><pre><code>reportDateLocal
</code></pre></td><td>Report Date Local Time</td><td>Used in combination with vessel code to locate the port call in Dataloy.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>berthed
</code></pre></td><td>Estimated Time of Berthing</td><td>Updates ETB in Schedule</td><td><br></td><td>Date</td><td><br></td></tr><tr><td><pre><code>departure
</code></pre></td><td>Estimated Time of Departure</td><td>Updates ETD in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>hoursInService
</code></pre></td><td>Hours in Service</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>weatherId
</code></pre></td><td>Weather. <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Inserted in Postion Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>windDirectionId
</code></pre></td><td>Wind Direction. <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a> </td><td>Inserted in Postion Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>averageWindForce
</code></pre></td><td>Average Wind Force. Beaufort.</td><td>Inserted in Postion Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>genericRemark
</code></pre></td><td>Remark</td><td>Inserted as a Remark to the Position Report.</td><td><br></td><td>String</td><td>Unlimited</td></tr></tbody></table>

### &#x20;**Departure Report**<br>

<table data-header-hidden><thead><tr><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>JSON Field Name</td><td>Description</td><td>Affects Dataloy VMS</td><td>Mandatory</td><td>Type</td><td>Length</td></tr><tr><td>portCallId</td><td>A port call id</td><td>If the port call id is available, use this to avoid VRS trying to locate the correct port call.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>referenceNo</td><td>Voyage reference number</td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td>reasonForCall</td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>  </td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td><pre><code>reportTypeCode
</code></pre></td><td>Vessel Report Type.<br>Value = DEP for Departure Report.</td><td>Used to insert the correct type of position report and to locate the correct port call.</td><td>Yes</td><td>String</td><td>4</td></tr><tr><td><pre><code>vesselCode
</code></pre></td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Used in combination with report date local time to locate the port call in Dataloy VMS.</td><td>Yes</td><td>String</td><td>6</td></tr><tr><td><pre><code>portId
</code></pre></td><td>Departure Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an error message will be returned and the report will not be inserted.</td><td>Yes</td><td>Integer</td><td>38</td></tr><tr><td><pre><code>reportDateLocal
</code></pre></td><td>Report Date Local Time</td><td>Used in combination with vessel code to locate the port call in Dataloy VMS.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>departure
</code></pre></td><td>Departure Time</td><td>Updates Estimated Time of Departure (ETD) in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>nextPortId
</code></pre></td><td>Next Arrival Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an e-mail will be sent to the operator and the report will not be inserted.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>arrival
</code></pre></td><td>Estimated Time of Arrival</td><td>Updates Estimate Time of Arrival (ETA) for next Arrival Port.</td><td><br></td><td>Date</td><td><br></td></tr><tr><td><pre><code>distanceToNextPort
</code></pre></td><td>Distance To Next Port</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>draftAft
</code></pre></td><td>Draft Aft</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>draftForward
</code></pre></td><td>Draft Forward</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFo
</code></pre></td><td>Fuel Oil Remaining on Board (FO RoB)</td><td>Updates Fuel Oil Remaining on Board (FO RoB) departure.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDo
</code></pre></td><td>Diesel Oil Remaining on Board (DO RoB)</td><td>Updates Diesel Oil Remaining on Board (DO RoB) departure.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFl
</code></pre></td><td>Fuel Oil Low Sulphur Remaining on Board (FO LS RoB)</td><td>Updates Fuel Oil Low Sulphur Remaining on Board (FO LS RoB) departure.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDl
</code></pre></td><td>Diesel Oil Low Sulphur Remaining on Board (DO LS RoB)</td><td>Updates Diesel Oil Low Sulphur Remaining on Board (FO LS RoB) departure.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFw
</code></pre></td><td>Fresh Water Remaining on Board</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>foBunkered
</code></pre></td><td>Bunkered Fuel Oil<br>Input Exact Figure According to BDR</td><td>Updates Fuel Oil bunkered for departure port call.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>flBunkered
</code></pre></td><td>Bunkered Fuel Oil Low Sulphur<br>Input exact figure according to the BDR</td><td>Updates Fuel Oil Low Sulphur bunkered for departure port call.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>doBunkered
</code></pre></td><td>Bunkered Diesel Oil<br>Input exact figure according to the BDR</td><td>Updates Diesel Oil bunkered for departure port call.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dlBunkered
</code></pre></td><td>Bunkered Diesel Oil Low Sulphur<br>Input exact figure according to the BDR</td><td>Updates Diesel Oil Low Sulphur bunkered for departure port call.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>genericRemark
</code></pre></td><td>Remark</td><td>Inserted as remark to position report.</td><td><br></td><td>String</td><td>Unlimited</td></tr></tbody></table>

### &#x20;**Example Messages**

Updated for [API version 2.0.0](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404316/Dataloy+API+2.0+Release+Notes) using the new required date format **yyyy-dd-MMThh:mi:ss** to conform ISO 8601, (prior version has date format: yyyy-dd-MM hh:mi:ss)

Arrival

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><p></p><pre class="language-postman_json"><code class="lang-postman_json">{
    "remarks": [],
    "events": [
        {
            "ed": "2013-12-24T00:00:00",
            "ec": "VR05"
        },
        {
            "ed": "2013-12-24T00:00:00",
            "ec": "VR10"
        }
    ],
    "reportTypeCode": "ARR",
    "vesselCode": "14",
    "portId": "104419",
    "reportDateLocal": "2013-12-24T00:00:00",
    "arrival": "2013-12-24T00:00:00",
    "berthed": "2013-12-24T00:00:00",
    "departure": "2013-12-24T00:00:00",
    "distanceSailed": "10",
    "distanceSailedSinceDeparture": "10",
    "hoursInService": "10",
    "hoursStoppages": "10",
    "speedMadeGood": "10",
    "draftAft": "10",
    "draftForward": "10",
    "dailyFo": "10",
    "dailyDo": "10",
    "dailyFl": "10",
    "dailyDl": "10",
    "dailyFw": "10",
    "robFo": "10",
    "robDo": "10",
    "robFl": "10",
    "robDl": "10",
    "robFw": "10",
    "genericRemark": "Remark"
}
</code></pre></td></tr></tbody></table>

Departure

| `{    "remarks":[        {            "id":"70495513",            "r":"10"        },        {            "id":"70495512",            "r":"10"        },        {            "id":"70495511",            "r":"10"        },        {            "id":"70495510",            "r":"10"        },        {            "id":"70495509",            "r":"10"        },        {            "id":"70495514",            "r":"10"        },        {            "id":"70495515",            "r":"10"        },        {            "id":"70495516",            "r":"10"        },        {            "id":"70495517",            "r":"10"        },        {            "id":"70495518",            "r":"10"        },        {            "id":"70495519",            "r":"10"        }    ],    "events":[        {            "ed":"2013-12-24T00:00:00",            "ec":"VR15"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR20"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR25"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR30"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR40"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR45"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR50"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR55"        }    ],    "reportTypeCode":"DEP",    "vesselCode":"14",    "portId":"104419",    "reportDateLocal":"2013-12-24T00:00:00",    "departure":"2013-12-24T00:00:00",    "nextPortId":"104419",    "arrival":"2013-12-24T00:00:00",    "distanceToNextPort":"10",    "draftAft":"10",    "draftForward":"10",    "robFo":"10",    "robDo":"10",    "robFl":"10",    "robDl":"10",    "robFw":"10",    "foBunkered":"10",    "flBunkered":"10",    "doBunkered":"10",    "dlBunkered":"10",    "genericRemark":"Remark"}` |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

Noon

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><p></p><pre class="language-postman_json"><code class="lang-postman_json">{
    "events": [],
    "reportTypeCode": "NOON",
    "vesselCode": "14",
    "latitude": 10.17,
    "longitude": 10.17,
    "portId": "104419",
    "reportDateLocal": "2013-12-24T00:00:00",
    "arrival": "2013-12-24T00:00:00",
    "berthed": "2013-12-24T00:00:00",
    "departure": "2013-12-24T00:00:00",
    "trueCourse": "10",
    "distanceSailed": "10",
    "hoursInService": "10",
    "distanceToNextPort": "10",
    "speedMadeGood": "10",
    "windDirectionId": "911638",
    "averageWindForce": "0",
    "seaDirectionId": "911638",
    "averageSeaState": "1",
    "bhpMainEngineIndicatedRpm": "10",
    "dailyFo": "10",
    "dailyDo": "10",
    "dailyFl": "10",
    "dailyDl": "10",
    "dailyFw": "10",
    "robFo": "10",
    "robDo": "10",
    "robFl": "10",
    "robDl": "10",
    "robFw": "10",
    "genericRemark": "Remark"
}
</code></pre></td></tr></tbody></table>

Port

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><p></p><pre class="language-postman_json"><code class="lang-postman_json">{
    "remarks": [
        {
            "id": "70495526",
            "r": "100"
        },
        {
            "id": "70495527",
            "r": "100"
        },
        {
            "id": "70495528",
            "r": "100"
        }
    ],
    "events": [
        {
            "ed": "2013-12-24T00:00:00",
            "ec": "VR60"
        }
    ],
    "reportTypeCode": "PORT",
    "vesselCode": "14",
    "portId": "104419",
    "reportDateLocal": "2013-12-24T00:00:00",
    "berthed": "2013-12-24T00:00:00",
    "departure": "2013-12-24T00:00:00",
    "hoursInService": "20",
    "weatherId": "950936",
    "windDirectionId": "913903",
    "averageWindForce": "1",
    "genericRemark": "Remark"
}
</code></pre></td></tr></tbody></table>

<br>

### **Consumption Breakdown**

The following fields can be added for consumption breakdown

| Main Engine - Fuel Oil                                                | Inserted to position report. |
| --------------------------------------------------------------------- | ---------------------------- |
| Main Engine - Fuel Oil Low Sulphur                                    | Inserted to position report. |
| Main Engine - Diesel Oil                                              | Inserted to position report. |
| Main Engine - Diesel Oil Low Sulphur                                  | Inserted to position report. |
| Auxiliary - Fuel Oil At Sea                                           | Inserted to position report. |
| Auxiliary - Fuel Oil Low Sulphur At Sea                               | Inserted to position report. |
| Auxiliary - Diesel Oil At Sea                                         | Inserted to position report. |
| Auxiliary - Diesel Oil Low Sulphur At SeaInserted to position report. | Inserted to position report. |
| Boilers - Fuel Oil Idle                                               | Inserted to position report. |
| Boilers - Fuel Oil Low Sulphur Idle                                   | Inserted to position report. |
| Boilers - Diesel Oil Idle                                             | Inserted to position report. |
| Boilers - Diesel Oil Low Sulphur Idle                                 | Inserted to position report. |
| Boilers - Fuel Oil Working                                            | Inserted to position report. |
| Boilers - Fuel Oil Low Sulphur Working                                | Inserted to position report. |
| Boilers - Diesel Oil Working                                          | Inserted to position report. |
| Boilers - Diesel Oil Low Sulphur Working                              | Inserted to position report. |
| Generators - Fuel Oil At Sea                                          | Inserted to position report. |
| Generators - Fuel Oil Low Sulphur At Sea                              | Inserted to position report. |
| Generators - Diesel Oil At Sea                                        | Inserted to position report. |
| Generators - Diesel Oil Low Sulphur At Sea                            | Inserted to position report. |
| Cleaning - Fuel Oil                                                   | Inserted to position report. |
| Cleaning - Fuel Oil Low Sulphur                                       | Inserted to position report. |
| Cleaning - Diesel Oil                                                 | Inserted to position report. |
| Cleaning - Diesel Oil Low Sulphur                                     | Inserted to position report. |
| Heating - Fuel Oil Consumption                                        | Inserted to position report. |
| Heating - Fuel Oil Low Sulphur                                        | Inserted to position report. |
| Heating - Diesel Oil                                                  | Inserted to position report. |
| Heating - Diesel Oil Low Sulphur                                      | Inserted to position report. |

<br>

### **Weather Data**

When inserting weather data, use the ID from the Weather Data table:

<table data-header-hidden><thead><tr><th width="411"></th><th></th></tr></thead><tbody><tr><td>Weather ID</td><td>Weather Description</td></tr><tr><td><pre><code>950926
</code></pre></td><td>Clear Sky</td></tr><tr><td><pre><code>950927
</code></pre></td><td>Sunny Day</td></tr><tr><td><pre><code>950928
</code></pre></td><td>Partly Cloudy</td></tr><tr><td><pre><code>950929
</code></pre></td><td>Sunny Intervals</td></tr><tr><td><pre><code>950930
</code></pre></td><td>Dust</td></tr><tr><td><pre><code>950931
</code></pre></td><td>Mist</td></tr><tr><td><pre><code>950932
</code></pre></td><td>Fog</td></tr><tr><td><pre><code>950933
</code></pre></td><td>Medium-Level Cloud</td></tr><tr><td><pre><code>950934
</code></pre></td><td>Low-Level Cloud</td></tr><tr><td><pre><code>950935
</code></pre></td><td>Light Rain Shower</td></tr><tr><td><pre><code>950936
</code></pre></td><td>Drizzle</td></tr><tr><td><pre><code>950937
</code></pre></td><td>Light Rain</td></tr><tr><td><pre><code>950938
</code></pre></td><td>Heavy Rain Shower</td></tr><tr><td><pre><code>950939
</code></pre></td><td>Heavy Rain</td></tr><tr><td><pre><code>950940
</code></pre></td><td>Sleet Shower</td></tr><tr><td><pre><code>950941
</code></pre></td><td>Sleet</td></tr><tr><td><pre><code>950942
</code></pre></td><td>Hail Shower</td></tr><tr><td><pre><code>950943
</code></pre></td><td>Hail</td></tr><tr><td><pre><code>950944
</code></pre></td><td>Light Snow Shower</td></tr><tr><td><pre><code>950945
</code></pre></td><td>Light Snow</td></tr><tr><td><pre><code>950946
</code></pre></td><td>Heavy Snow Shower</td></tr><tr><td><pre><code>950947
</code></pre></td><td>Heavy Snow</td></tr><tr><td><pre><code>950948
</code></pre></td><td>Thundery Shower</td></tr><tr><td><pre><code>950949
</code></pre></td><td>Thunder Storm</td></tr><tr><td><pre><code>950950
</code></pre></td><td>Tropical Storm</td></tr><tr><td><pre><code>950951
</code></pre></td><td>Haze</td></tr></tbody></table>

### **Direction**

When inserting direction, use the ID from the Direction Table:

<table data-header-hidden><thead><tr><th></th><th></th></tr></thead><tbody><tr><td>Direction id</td><td>Direction Description</td></tr><tr><td><pre><code>911636
</code></pre></td><td>North</td></tr><tr><td><pre><code>911637
</code></pre></td><td>South</td></tr><tr><td><pre><code>911638
</code></pre></td><td>East</td></tr><tr><td><pre><code>911639
</code></pre></td><td>West</td></tr><tr><td><pre><code>911640
</code></pre></td><td>North/East</td></tr><tr><td><pre><code>911641
</code></pre></td><td>North/West</td></tr><tr><td><pre><code>911642
</code></pre></td><td>South/East</td></tr><tr><td><pre><code>911643
</code></pre></td><td>South/West</td></tr><tr><td><pre><code>913753
</code></pre></td><td>Various</td></tr><tr><td><pre><code>913902
</code></pre></td><td>North/North/East</td></tr><tr><td><pre><code>913903
</code></pre></td><td>East/North/East</td></tr><tr><td><pre><code>913904
</code></pre></td><td>East/South/East</td></tr><tr><td><pre><code>913905
</code></pre></td><td>South/South/East</td></tr><tr><td><pre><code>913906
</code></pre></td><td>South/South/West</td></tr><tr><td><pre><code>913907
</code></pre></td><td>West/South/West</td></tr><tr><td><pre><code>913908
</code></pre></td><td>West/North/West</td></tr><tr><td><pre><code>913909
</code></pre></td><td>North/North/West</td></tr><tr><td><pre><code>916765
</code></pre></td><td>East/by/North</td></tr><tr><td><pre><code>916766
</code></pre></td><td>East/by/South</td></tr><tr><td><pre><code>916767
</code></pre></td><td>North/by/East</td></tr><tr><td><pre><code>916768
</code></pre></td><td>North/by/West</td></tr><tr><td><pre><code>916769
</code></pre></td><td>NE/by/East</td></tr><tr><td><pre><code>916770
</code></pre></td><td>NE/by/north</td></tr><tr><td><pre><code>916771
</code></pre></td><td>NW/by/North</td></tr><tr><td><pre><code>916772
</code></pre></td><td>NW/by/West</td></tr><tr><td><pre><code>916773
</code></pre></td><td>SE/by/East</td></tr><tr><td><pre><code>916774
</code></pre></td><td>SE/by/South</td></tr><tr><td><pre><code>916775
</code></pre></td><td>SW/by/South</td></tr><tr><td><pre><code>916776
</code></pre></td><td>SW/by/West</td></tr><tr><td><pre><code>916777
</code></pre></td><td>South/by/East</td></tr><tr><td><pre><code>916778
</code></pre></td><td>South/by/West</td></tr><tr><td><pre><code>916779
</code></pre></td><td>West/by/North</td></tr><tr><td><pre><code>916780
</code></pre></td><td>West/by/South</td></tr></tbody></table>

### **Reason For Call**

| Code | Description          |
| ---- | -------------------- |
| L    | Loading              |
| D    | Discharging          |
| C    | Canal Passage        |
| E    | Extra Port           |
| DD   | Dry Dock             |
| DEL  | Delivery             |
| RED  | Redelivery           |
| B    | Bunkering            |
| R    | Repair               |
| CL   | Tank / Hold Cleaning |
| STS  | Ship to Ship         |
| W    | Waiting              |
| CC   | Customs Clearance    |

<br>

<br>

### **Dataloy Vessel Code**

Dataloy Vessel Codes can be found by using the [Vessel Code Resource](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F6.46/model/schemas/vessel-code).

### **Dataloy Port ID**

Dataloy Port ID's can be found be using the [Port Resource](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F6.46/model/schemas/port).


# Vessel report master data

### Direction data

<table data-header-hidden><thead><tr><th></th><th></th></tr></thead><tbody><tr><td>Direction id</td><td>Direction Description</td></tr><tr><td><pre><code>911636
</code></pre></td><td>North</td></tr><tr><td><pre><code>911637
</code></pre></td><td>South</td></tr><tr><td><pre><code>911638
</code></pre></td><td>East</td></tr><tr><td><pre><code>911639
</code></pre></td><td>West</td></tr><tr><td><pre><code>911640
</code></pre></td><td>North/East</td></tr><tr><td><pre><code>911641
</code></pre></td><td>North/West</td></tr><tr><td><pre><code>911642
</code></pre></td><td>South/East</td></tr><tr><td><pre><code>911643
</code></pre></td><td>South/West</td></tr><tr><td><pre><code>913753
</code></pre></td><td>Various</td></tr><tr><td><pre><code>913902
</code></pre></td><td>North/North/East</td></tr><tr><td><pre><code>913903
</code></pre></td><td>East/North/East</td></tr><tr><td><pre><code>913904
</code></pre></td><td>East/South/East</td></tr><tr><td><pre><code>913905
</code></pre></td><td>South/South/East</td></tr><tr><td><pre><code>913906
</code></pre></td><td>South/South/West</td></tr><tr><td><pre><code>913907
</code></pre></td><td>West/South/West</td></tr><tr><td><pre><code>913908
</code></pre></td><td>West/North/West</td></tr><tr><td><pre><code>913909
</code></pre></td><td>North/North/West</td></tr><tr><td><pre><code>916765
</code></pre></td><td>East/by/North</td></tr><tr><td><pre><code>916766
</code></pre></td><td>East/by/South</td></tr><tr><td><pre><code>916767
</code></pre></td><td>North/by/East</td></tr><tr><td><pre><code>916768
</code></pre></td><td>North/by/West</td></tr><tr><td><pre><code>916769
</code></pre></td><td>NE/by/East</td></tr><tr><td><pre><code>916770
</code></pre></td><td>NE/by/north</td></tr><tr><td><pre><code>916771
</code></pre></td><td>NW/by/North</td></tr><tr><td><pre><code>916772
</code></pre></td><td>NW/by/West</td></tr><tr><td><pre><code>916773
</code></pre></td><td>SE/by/East</td></tr><tr><td><pre><code>916774
</code></pre></td><td>SE/by/South</td></tr><tr><td><pre><code>916775
</code></pre></td><td>SW/by/South</td></tr><tr><td><pre><code>916776
</code></pre></td><td>SW/by/West</td></tr><tr><td><pre><code>916777
</code></pre></td><td>South/by/East</td></tr><tr><td><pre><code>916778
</code></pre></td><td>South/by/West</td></tr><tr><td><pre><code>916779
</code></pre></td><td>West/by/North</td></tr><tr><td><pre><code>916780
</code></pre></td><td>West/by/South</td></tr></tbody></table>

### Weather data

<table data-header-hidden><thead><tr><th width="411"></th><th></th></tr></thead><tbody><tr><td>Weather ID</td><td>Weather Description</td></tr><tr><td><pre><code>950926
</code></pre></td><td>Clear Sky</td></tr><tr><td><pre><code>950927
</code></pre></td><td>Sunny Day</td></tr><tr><td><pre><code>950928
</code></pre></td><td>Partly Cloudy</td></tr><tr><td><pre><code>950929
</code></pre></td><td>Sunny Intervals</td></tr><tr><td><pre><code>950930
</code></pre></td><td>Dust</td></tr><tr><td><pre><code>950931
</code></pre></td><td>Mist</td></tr><tr><td><pre><code>950932
</code></pre></td><td>Fog</td></tr><tr><td><pre><code>950933
</code></pre></td><td>Medium-Level Cloud</td></tr><tr><td><pre><code>950934
</code></pre></td><td>Low-Level Cloud</td></tr><tr><td><pre><code>950935
</code></pre></td><td>Light Rain Shower</td></tr><tr><td><pre><code>950936
</code></pre></td><td>Drizzle</td></tr><tr><td><pre><code>950937
</code></pre></td><td>Light Rain</td></tr><tr><td><pre><code>950938
</code></pre></td><td>Heavy Rain Shower</td></tr><tr><td><pre><code>950939
</code></pre></td><td>Heavy Rain</td></tr><tr><td><pre><code>950940
</code></pre></td><td>Sleet Shower</td></tr><tr><td><pre><code>950941
</code></pre></td><td>Sleet</td></tr><tr><td><pre><code>950942
</code></pre></td><td>Hail Shower</td></tr><tr><td><pre><code>950943
</code></pre></td><td>Hail</td></tr><tr><td><pre><code>950944
</code></pre></td><td>Light Snow Shower</td></tr><tr><td><pre><code>950945
</code></pre></td><td>Light Snow</td></tr><tr><td><pre><code>950946
</code></pre></td><td>Heavy Snow Shower</td></tr><tr><td><pre><code>950947
</code></pre></td><td>Heavy Snow</td></tr><tr><td><pre><code>950948
</code></pre></td><td>Thundery Shower</td></tr><tr><td><pre><code>950949
</code></pre></td><td>Thunder Storm</td></tr><tr><td><pre><code>950950
</code></pre></td><td>Tropical Storm</td></tr><tr><td><pre><code>950951
</code></pre></td><td>Haze</td></tr></tbody></table>


# Bunker Consumption API

### Consumption and bunker related figures for a given voyage are stored in VoyageBunker and Rob resources

### VoyageBunker - Bunker summary of entire voyage

Each voyage is linked to one VoyageBunker object for each bunker category that is used during the voyage. VoyageBunker stores the following information/fields:

* **bunkerCategory**: the BunkerCategory connected to the VoyageBunker object
* **consumption**: total consumption of the bunker during the voyage
* **cost**: total bunker cost during the voyage
* **price**:  average bunker price during the voyage
* **priceVoyageStart**: average bunker price at voyage start
* **priceVoyageEnd**: average bunker price at voyage end
* **profitLoss**: the charterer's total bunker profit/loss
* **profitLossTcIn**: the owner's total bunker profit/loss
* **robDelivery**: bunker ROB at delivery port
* **robRedelivery**: bunker ROB at redelivery port
* **robVoyageStart**: bunker ROB at voyage start
* **voyage**: the Voyage connected to the VoyageBunker

The following request fetches all VoyageBunker objects for a given voyage:\
\
`https://BASE_URL/ws/rest/VoyageBunker?filter=voyage.key(EQ)20012412`

Alternatively, a request can be sent against /Voyage/20012412 with *voyageBunkers* defined in the header fields. The JSON below is an example response of above requests. Two different bunkers are used during this voyage, *FO* and *LS MGO*.

```json
[
    {
        "key": 20027578,
        "self": "https://BASE_URL/ws/rest/VoyageBunker/20027578",
        "bunkerCategory": {
            "key": 13575292,
            "self": "https://BASE_URL/ws/rest/BunkerCategory/13575292",
            "bunkerCategoryName": "FO",
        },
        "consumption": 530.0,
        "cost": 359340.0,
        "price": 678.0,
        "priceVoyageStart": 678.0,
        "priceVoyageEnd": 678.0,
        "profitLoss": 0.0,
        "profitLossTcIn": 0.0,
        "robDelivery": 0.0,
        "robRedelivery": 0.0,
        "robVoyageStart": 600.0,
        "voyage": {
            "key": 20012412,
            "self": "https://BASE_URL/ws/rest/Voyage/20012412",
        }
    },
    {
        "key": 20027579,
        "self": "https://BASE_URL/ws/rest/VoyageBunker/20027579",
        "bunkerCategory": {
            "key": 13575293,
            "self": "https://BASE_URL/ws/rest/BunkerCategory/13575293",
            "bunkerCategoryName": "LS MGO",
        },
        "consumption": 120.0,
        "cost": 93240.0,
        "price": 777.0,
        "priceVoyageStart": 777.0,
        "priceVoyageEnd": 777.0,
        "profitLoss": 0.0,
        "profitLossTcIn": 0.0,
        "robDelivery": 0.0,
        "robRedelivery": 0.0,
        "robVoyageStart": 200.0,
        "voyage": {
            "key": 20012412,
            "self": "https://BASE_URL/ws/rest/Voyage/20012412",
        }
    }
]
```

### Rob - Bunkers per leg&#x20;

*Rob = remaining on board.*\
\
Rob objects stores bunker related numbers for a single leg on the Voyage. A Rob is connected to a PortCall through EventLogs. Each EventLog contains an underlying Event with an eventCode attribute, and there are four eventCodes relevant for Robs - 'ARR', 'BRT', 'UBRT', and 'DEP', corresponding to Arrival, Berth, Unberth, and Departure, respectively.&#x20;

As an example, the following request can be used to fetch all Robs for a given EventLog:

`https://BASE_URL/ws/rest/EventLog/20027578`

Assuming this EventLog is linked to the *arrival* event, the returned Robs contains at-sea consumption from previous port call, and fuel remaining upon arrival (for each bunker). Below is an example JSON response:

```json
{
    "key": 20027578,
    "self": "https://BASE_URL/ws/rest/EventLog/20027578",
    "event": {
        "key": 13575292,
        "self": "https://BASE_URL/ws/rest/Event/13575292",
        "eventCode": "UBRT"
    },
    "robs": [
        {
            "key": 20027642,
            "self": "https://BASE_URL/ws/rest/Rob/20027642",
            "bunkerCategory": {
                "key": 916944,
                "self": "https://BASE_URL/ws/rest/BunkerCategory/916944",
                "bunkerCategoryCode": "FO"
            },
            "robFixed": false,
            "rob": 0.0,
            "consumption": 0.0
        },
        {
            "key": 20027649,
            "self": "https://BASE_URL/ws/rest/Rob/20027649",
            "bunkerCategory": {
                "key": 916947,
                "self": "https://BASE_URL/ws/rest/BunkerCategory/916947",
                "bunkerCategoryCode": "DL"
            },
            "robFixed": false,
            "rob": -4.61125655636663,
            "consumption": 0.0
        },
        {
            "key": 20027651,
            "self": "https://BASE_URL/ws/rest/Rob/20027651",
            "bunkerCategory": {
                "key": 916945,
                "self": "https://BASE_URL/ws/rest/BunkerCategory/916945",
                "bunkerCategoryCode": "FL"
            },
            "robFixed": false,
            "rob": 0.0,
            "consumption": 0.0
        },
        {
            "key": 20027663,
            "self": "https://BASE_URL/ws/rest/Rob/20027663",
            "bunkerCategory": {
                "key": 916946,
                "self": "https://BASE_URL/ws/rest/BunkerCategory/916946",
                "bunkerCategoryCode": "DO"
            },
            "robFixed": false,
            "rob": 0.0,
            "consumption": 0.0
        }
    ]
}
```

*Note! To get the same response, the following header fields must be specified:* `{"event":{"eventCode":"*"},"robs": {"`*`consumption":"*"`*`,"robFixed":"*"`*`,"rob": "*"`*`,"bunkerCategory":{"bunkerCategoryCode":"*"}}}`

To retrieve a list of Robs for a given EventLog, use the "robs" field. The number of Robs returned corresponds to the number of BunkerCategories in the system.

### Rob fields

```
{
  "eventLog": {},
  "robFixed": true,
  "bunkerCategory": {},
  "rob": -1.7976931348623157e+308,
  "consumption": -1.7976931348623157e+308
}
```

Attributes breakdown:

* bunkerCategory - the BunkerCategory connected to the Rob
* eventLog - the EventLog connected to the Rob
* rob - remaining fuel onboard
* consumption - the bunker consumption between previous event and the connected event
* robFixed - identifies whether the rob value is fixed or not

### How do we get the total consumption for a Port Call?

To get total consumption for a Port Call, Robs for all EventLogs on the PortCalls must be acquired.

The list of all EventLogs can be referenced directly from a PortCall:

Header fields: `{"eventLogs": {"event":{"eventCode":"*"},"robs": {"`*`consumption":"*"`*`,"robFixed":"*"`*`,"rob": "*"`*`,"bunkerCategory":{"bunkerCategoryCode":"*"}}}}`

Response:

```
{
    "key": 20027590,
    "self": "https://BASE_URL/ws/rest/PortCall/20027590",
    "eventLogs": [
        {
            "key": 20027578,
            "self": "https://BASE_URL/ws/rest/EventLog/20027578",
            "event": {
                "key": 13575292,
                "self": "https://BASE_URL/ws/rest/Event/13575292",
                "eventCode": "UBRT"
            },
            "robs": [
                {
                    "key": 20027642,
                    "self": "https://BASE_URL/ws/rest/Rob/20027642",
                    "bunkerCategory": {
                        "key": 916944,
                        "self": "https://BASE_URL/ws/rest/BunkerCategory/916944",
                        "bunkerCategoryCode": "FO"
                    },
                    "robFixed": false,
                    "rob": 0.0,
                    "consumption": 0.0
                },
                {
                    "key": 20027649,
                    "self": "https://BASE_URL/ws/rest/Rob/20027649",
                    "bunkerCategory": {
                        "key": 916947,
                        "self": "https://BASE_URL/ws/rest/BunkerCategory/916947",
                        "bunkerCategoryCode": "DL"
                    },
                    "robFixed": false,
                    "rob": -4.61125655636663,
                    "consumption": 0.0
                },
                {
                    "key": 20027651,
                    "self": "https://BASE_URL/ws/rest/Rob/20027651",
                    "bunkerCategory": {
                        "key": 916945,
                        "self": "https://BASE_URL/ws/rest/BunkerCategory/916945",
                        "bunkerCategoryCode": "FL"
                    },
                    "robFixed": false,
                    "rob": 0.0,
                    "consumption": 0.0
                },
                {
                    "key": 20027663,
                    "self": "https://BASE_URL/ws/rest/Rob/20027663",
                    "bunkerCategory": {
                        "key": 916946,
                        "self": "https://BASE_URL/ws/rest/BunkerCategory/916946",
                        "bunkerCategoryCode": "DO"
                    },
                    "robFixed": false,
                    "rob": 0.0,
                    "consumption": 0.0
                }
            ]
        },
        {
            "key": 20027584,
            "self": "https://BASE_URL/ws/rest/EventLog/20027584",
            "event": {
                "key": 1000051,
                "self": "https://BASE_URL/ws/rest/Event/1000051",
                "eventCode": "BRT"
            },
            "robs": [
                {
...
```

The output will consist of four EventLog objects, each containing four robs, making a total of sixteen robs (calculated by multiplying the number of event logs by four bunker categories). By adding up all the consumption attributes, you can get the total consumption per leg


# Market Index Integration API

**A market index integration** will allow you to continuously feed the Dataloy VMS with updated market rates. From this data, Dataloy VMS can calculate accurate rates automatically, removing cumbersome manual work and reducing the risk of errors.

{% hint style="info" %}
At this point in time, only Market Indices of type TC Rate is used for automatic calculations. Indices of other types will be for information only.
{% endhint %}

The [MarketIndex](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index) entity is a simple object; a name, unique code property, and a list of [MarketIndexValues](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index-value). The MarketIndexValues consists of a date from which it is valid from, a date to which it is valid to, a type signifying if it is current or archived, and a numeric value.


# TC Rate Market Indices

## Calculation overview

When making changes to a TC Rate Market Index - by adding or editing a MarketIndexValue - the following related objects will be recalculated:

* [MarketIndexValue](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index-value)
* [MarketIndex](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index) (validation only)
* [MarketIndex](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index)&#x20;
  * Any custom market index that have the market index you are editing of adding a market index value to will be recalculated if all other market indices in the custom market index has been updated today
* [TcRate](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/tc-rate)
* [TcDuration](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/tc-duration)
* [Tc](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/tc)
* [Offhire](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/offhire)
* [Voyage](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/voyage)

Recalculation is triggered by a **POST** or **PUT** request on the **MarketIndexValue** endpoint. The scope of objects being recalculated is limited by the **validFrom** date on the **MarketIndexValue**; such that, for instance, a voyage that ends before the **validFrom** date is not recalculated.

**DELETE** requests do not trigger a recalculation at this time. Validation will still run when deleting, and deleting a market index value for a market index that is part of a custom market index is not allowed.

## Workflow

### **Step 1: Bulk Updating Forward Estimates/Rates**

In order to update multiple index values at once, it is recommended to use the [BulkUpdateIncrement](/api-release-8.26/user-guides/enterprise-functionality/bulk-update-increment) feature.&#x20;

{% hint style="warning" %}
While it is possible to trigger all recalculations at once, it is **highly** recommended to add the header *disablebl* with value set to *true* when using the BulkUpdateIncrement feature on MarketIndexValues. This is in order to mitigate calculation costs, and concurrency problems for objects with overlapping.
{% endhint %}

Example:

```
https://{host}/ws/rest/MarketIndexValue/bulkUpdateIncrement
```

```json
[
  {
    "key":{marketIndexValueKey1},
    "validFromDate": "2026-03-01T00:00:00",
    "validToDate": "2026-03-31T00:00:00",
    "marketIndexValue": 5300
  },
  {
    "key":{marketIndexValueKey2},
    "validFromDate": "2026-04-01T00:00:00",
    "validToDate": "2026-04-30T00:00:00",
    "marketIndexValue": 6400
  },
  {
    "key":{marketIndexValueKey3},
    "validFromDate": "2026-01-01T00:00:00",
    "validToDate": "2026-04-30T00:00:00",
    "marketIndexValue": 7000
  },
  {
    "key":{marketIndexValueKey4},
    "validFromDate": "2026-05-1T00:00:00",
    "validToDate": "2026-05-31T00:00:00",
    "marketIndexValue": 7100
  }
]
```

### **Step 2: Updating todays MarketIndexValue**

We can now update todays MarketIndexValue, and trigger a recalculation of all related objects.&#x20;

#### **Option A: PUT on existing MarketIndexValue**

```
https://{host}/ws/rest/MarketIndexValue/{key}
```

```json
{
    "marketIndexValue": 10250
}
```

#### **Option B: POST a new MarketIndexValue**

```
https://{host}/ws/rest/MarketIndexValue
```

```json
{
    "marketIndex": {marketIndexCode},
    "marketIndexValue": 10400,
    "validFromDate": "2025-07-08T00:00:00",
    "publishedDate": "2025-07-08T00:00:00"
}
```

Posting a market index value without:

* marketIndexValueType :
  * Will default to SPOT if either&#x20;
    * ValidFromDate is null
    * validToDate is null
    * ValidFromDate == ValidToDate
  * Else it will get FORWARD
* ValidFromDate
  * If market index value is SPOT
    * Will use ValidToDate
  * Else will fail at validation since valid from date is required
* ValidToDate
  * If market index value is SPOT
    * Will use ValidFromDate
  * Else will fail at validation since validToDate is required
* PublishedDate
  * If market index value is SPOT
    * Sets PublishedDate = ValidFromDate
  * Else
    * Todays date at 00:00 UTC+0


# Left join in API queries

The default behavior when an API query is executed is to put in right join the relationship between objects. From DLP 4.0.0 is possible specify in the filters of the API URL query to use left join instead of the right join.

For instance the following API query: [http://platform-dev.dataloy.com/ws/rest/Cargo?pageNumber=1\&limit=50\&filter=voyage.voyageHeader.isBudget(EQ)0\&filter=(OR)\&filter=voyage(NULL)](http://localhost:8080/ws/rest/Cargo?pageNumber=1\&limit=5\&filter=voyage%2B.voyageHeader%2B.isBudget\(EQ\)0\&filter=\(OR\)\&filter=voyage\(NULL\))

generates the following SQL query:

```
SELECT t0.CARGO_ID AS c0
FROM TBL_CARGO t0 JOIN TBL_VOYAGE t1 ON (t0.VOYAGE_ID = t1.VOYAGE_ID) JOIN TBL_VOYAGE_HEADER t2 ON (t1.VOYAGE_ID = t2.VOYAGE_ID)
WHERE ((t2.IS_BUDGET = 0) OR (t0.VOYAGE_ID IS NULL))
```

That will not return cargoes with voyages null.

Instead if the following query is executed:&#x20;

[http://platform-dev.dataloy.com/ws/rest/Cargo?pageNumber=1\&limit=50\&filter=voyag&#x65;**+**.voyageHeade&#x72;**+**.isBudget(EQ)0\&filter=(OR)\&filter=voyage(NULL)](http://localhost:8080/ws/rest/Cargo?pageNumber=1\&limit=5\&filter=voyage%2B.voyageHeader%2B.isBudget\(EQ\)0\&filter=\(OR\)\&filter=voyage\(NULL\))

encoded (+ become %2B):

[http://platform-dev.dataloy.com/ws/rest/Cargo?pageNumber=1\&limit=50\&filter=voyag&#x65;**%2B**.voyageHeade&#x72;**%2B**.isBudget(EQ)0\&filter=(OR)\&filter=voyage(NULL)](http://localhost:8080/ws/rest/Cargo?pageNumber=1\&limit=5\&filter=voyage%2B.voyageHeader%2B.isBudget\(EQ\)0\&filter=\(OR\)\&filter=voyage\(NULL\))

generates the following SQL query:

```
SELECT t0.CARGO_ID AS c0
FROM TBL_CARGO t0 LEFT JOIN TBL_VOYAGE t1 ON (t0.VOYAGE_ID = t1.VOYAGE_ID) LEFT JOIN TBL_VOYAGE_HEADER t2 ON (t1.VOYAGE_ID = t2.VOYAGE_ID)
WHERE ((t2.IS_BUDGET = 0) OR (t0.VOYAGE_ID IS NULL))
```

It will return also cargoes with voyage null.

The same concept is used with **sort**:

Executing this query:

[http://platform-dev.dataloy.com/ws/rest/Cargo?sort=voyage.voyageHeader.referenceNo(AS)](http://localhost:8080/ws/rest/Cargo?sort=voyage%2B.voyageHeader%2B.referenceNo\(AS\))

the following SQL query is executed:

```

SELECT  t0.CARGO_ID  FROM TBL_CARGO t0
     JOIN TBL_VOYAGE t2
    ON (t0.VOYAGE_ID = t2.VOYAGE_ID)
     JOIN TBL_VOYAGE_HEADER t3
    ON (t2.VOYAGE_ID = t3.VOYAGE_ID)
    ORDER BY t3.REFERENCE_NO
```

Instead running the following query:

[http://platform-dev.dataloy.com/ws/rest/Cargo?sort=voyag&#x65;**%2B**.voyageHeade&#x72;**%2B**.referenceNo(AS)](http://localhost:8080/ws/rest/Cargo?sort=voyage%2B.voyageHeader%2B.referenceNo\(AS\))

the following SQL query is executed:

```
SELECT  t0.CARGO_ID  FROM TBL_CARGO t0
     LEFT JOIN TBL_VOYAGE t2
    ON (t0.VOYAGE_ID = t2.VOYAGE_ID)
     LEFT JOIN TBL_VOYAGE_HEADER t3
    ON (t2.VOYAGE_ID = t3.VOYAGE_ID)
    ORDER BY t3.REFERENCE_NO
```


# Enterprise functionality


# Versioning

**From**[ **version 2.10**](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404364/Dataloy+API+2.10+Release+Notes) it is possible to have multiple versions of Dataloy API deployed on an application server. New API functionalities can be utilized for certain clients while at the same time continue to use older API versions for other clients. This usage of the system can remain until all clients are tested and working with the latest Dataloy API version. The API version is specified in the URL.

**Latest Version**

The latest version of Dataly API deployed at a customer's application server remains available at:&#x20;

| `http://[ip]:[port]/ws/rest` |
| ---------------------------- |

Older versions can be located at **ws/rest/version-number**. For example, if version 2.10.0 is deployed it will be found at:

| `http://[ip]:[port]/ws/rest/6.38.0` |
| ----------------------------------- |


# Endpoint access control

Is possible restrict access to any endpoint.

In order for a user to get access to a given API Endpoint, the user must belong to a SecurityRole that has a SecurityPermission for the API Endpoint.

<figure><img src="/files/lj2NBxrsEJFPqpSyaWF5" alt=""><figcaption></figcaption></figure>

he endpoint access control is done also against the objects requested using  the ***fields*** JSON in the HTTP  Header. So for instance if the endpoint Vessel.GET is present and the user  does not belong to a SecurityRole that has a SecurityPermission for the Vessel.GET endpoint, requesting the Voyage resource specifying the following JSON in the fields parameter will get unauthorized (HTTP 401):

```
{ 
   "vessel":{ 
      "vesselName":"*",
      "auxEngine":"*"
   }
}
```

\
If the same user requests with the following JSON, it will get access because vesselName attribute is part of the minimal view of Vessel resource:

```
{ 
   "vessel":{ 
      "vesselName":"*"
   }
}
```

The same access control is performed when a WebhookSubscription is requested. If the user tries to subscribe for an object that has an Endpoint in the system, the subscription will be created only if the user can access to the Endpoint, otherwise Bad request (HTTP 400) exception will be thrown. <br>

To create a new Endpoint it has to be used the endpoint /ws/rest/Endpoint posting a JSON like this:

```
{
    "resourceName": "Vessel",
    "path": ".",
    "httpMethodType": "GET"
}
```

To create a new SecurityPermission it has to be used the endpoint /ws/rest/SecurityPermission posting a JSON like this:

```
{
    "endpoint": 335928937,
    "permissionName": "Bank.GET",
    "permissionType":  335343886
}
```

To create a new SecurityRole. Post the following JSON to /ws/rest/SecurityRole:

```

{
    "roleName":"testRole"  
}
```

To add a SecurityPermission to a SecurityRole. Post the following JSON to /ws/rest/SecurityRole:

```

{
    "securityPermissions": [
        {
            "key":335928939
        }
    ]
     
}
```

To add a SecurityRole to a User. Post the following JSON to /ws/rest/SecurityRole:

```

{
     
    "securityRoles": [
        {
            "key":335927922
        }
    ]
}
```


# Data access control via target object

Through DataControl objects is possible control the access to data  of the logged user for a given object connected to the target.&#x20;

For instance if we want to give access only to voyages connected with the business units that the user belong to, a DataControl object like this has to be posted:

```

{
    "matcherTarget": "BusinessUnit",
    "matcherAttributeTarget": "users.key",
    "objectName": "Voyage",
    "attribute": "voyageHeader.businessUnit"
}
```

* **matcherTarget** defines the Dataloy object that has to be used as target object
* **matherAttributeTarget** defines the attribute in the object target that links the object with the user
* **objectName** the Dataloy object that has to be applied the access control
* **attribute** the attribute name that link the  Dataloy object with the target object


# Data access control via target object and security role

Through the DataControl object it is possible to control data access for a target user(s) for a given object connected to the target by checking if the user(s) belongs to a given role.

For example, if we want to limit access for the captain of a vessel to only be able to view voyages of their vessel, a DataControl object like this has to be posted:

```
{
    "matcherTarget": "User",
    "matcherAttributeTarget": "key",
    "objectName": "Voyage",
    "attribute": "voyageHeader.vesselCodes.masterUser",
    "dataControlRoleValues":[
    	{"role": "MASTER_ONLINE_VESSEL"}
    ]
}
```

* **matcherTarget** defines the Dataloy object that has to be used as target object
* **matcherAttributeTarget** defines the attribute in the matcherTarget object that has to be used against the attribute of the object (objectName)
* **objectName** the Dataloy object that has to be applied the access control
* **attribute** the attribute name that links the Dataloy object with the target object
* **dataControlRoleValues** list of SecurityRole that the DataControl will be applied

In the above example if an User that belong to the SecurityRole "MATER\_ONLINE\_VESSEL" make a query to the endpoint Voyage, the server will return only the voyages that has voyageHeader.vesselCodes.masterUser = {the user that made the query}


# Data access control at object level

Through DataControl and DataControlRoleValue is possible to give access only to some specific objects.&#x20;

For instance if we want that the users that belong to the security role with key **59552772** can have access only to the documents connected with the business partner with key 20867070 and 22210381, a DataContol object like this has to be posted:

```
{
    "objectName": "Document",
    "attribute": "businessPartner.key",
    "dataControlRoleValues": [
        {
            "role":  59552772
            "valueType": "Long",
            "value": "20867070"
        },
        {
            "role": 59552772,
            "valueType": "Long",
            "value": "22210381"
        }
    ]
}
```

* **objectName** the Dataloy object that has to be applied the access control
* **attribute** the attribute name to be used to restrict the access
* **role** the security role that will use the access control (use the key, as role names containing spaces might not work)
* **value** the value to use as filter to restrict data
* **valueType** the type of the value (Integer, String)


# Fields access control

It is possible to create SecurityRole that remove the access to a set of fields of a given resource, both in read and write mode.&#x20;

For example it is possible to create a role that remove the access to the voyageResult field of the Voyage resource

All the users that will have such role, in the response of the Voyage resource, the field voyageResult will be not present.

POST: [http://dataloy.com/ws/rest/SecurityRole](http://platform-dev.dataloy.com/ws/rest/SecurityRole)

```
{
    "roleName": "VoyageResult",
    "attributeForbiddens": [
        {
            "objectName": "Voyage",
            "attributeName": "voyageResult",
            "read": true,
            "write": true
             
        }
  ]
}
```


# Alert Scripts

It is possible to create scripts, written in pseudo Java, that can be injected at runtime and used by Webhooks and Websockets.

An Alert Script can be very simple or very complex, their scope is to evaluate conditions and return true or false. If the script returns true the message is sent.

Alerts can be created and installed at run-time into the system. These are the predefined alerts available:

### Bunker price <a href="#alertscripts-bunkerprice" id="alertscripts-bunkerprice"></a>

```
import com.dataloy.ds.*;
import com.dataloy.*;
import java.math.*;
BunkerOrderLine bunkerOrderLineOld= null;
BunkerOrderLine bunkerOrderLineNew= null;
if(dlpObject instanceof BunkerOrderLine)
    bunkerOrderLineNew=  dlpObject;
if(oldDlpObject instanceof BunkerOrderLine)
    bunkerOrderLineOld=  oldDlpObject;
if( bunkerOrderLineOld!=null && bunkerOrderLineNew!=null && ((bunkerOrderLineOld.getUnitPrice()==null && bunkerOrderLineNew.getUnitPrice()!=null) || (bunkerOrderLineOld.getUnitPrice()!=null && bunkerOrderLineNew.getUnitPrice()==null) ||    !bunkerOrderLineNew.getUnitPrice().equals(bunkerOrderLineOld.getUnitPrice()))){
    mapResultsForMessage.put("?1",bunkerOrderLineNew.getBunkerType().getBunkerTypeDesc());
    mapResultsForMessage.put("?2",bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getVessel().getVesselName());
    if(bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getVoyageHeader()!= null && bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getVoyageHeader().getReferenceNo()!=null)
        mapResultsForMessage.put("?3",bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getVoyageHeader().getReferenceNo());
    else
        mapResultsForMessage.put("?3",bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getKey());
     
    mapResultsForMessage.put("?4",bunkerOrderLineNew.getBunkerOrder().getPortCall().getPort().getPortName());
     
    Double value1= new BigDecimal(bunkerOrderLineNew.getUnitPrice()).setScale(2, RoundingMode.HALF_UP).doubleValue();
    Double value2= new BigDecimal(bunkerOrderLineOld.getUnitPrice()).setScale(2, RoundingMode.HALF_UP).doubleValue();
     
     
    String strValue1= value1.toString();
    String appValue1= strValue1.substring(strValue1.indexOf(".")+1, strValue1.length());
    while(appValue1.length()<2)
        appValue1= appValue1 +0;
    String finalValue1= strValue1.substring(0,strValue1.indexOf(".")+1)+appValue1;
     
     
    String strValue2= value2.toString();
    String appValue2= strValue2.substring(strValue2.indexOf(".")+1, strValue2.length());
    while(appValue2.length()<2)
        appValue2= appValue2 +0;
    String finalValue2= strValue2.substring(0,strValue2.indexOf(".")+1)+appValue2;
     
     
    mapResultsForMessage.put("?5",finalValue1  );
    mapResultsForMessage.put("?6",finalValue2  );
     
     
    return true;
}
else{
    return false;
}
```

### Bunker quantity <a href="#alertscripts-bunkerquantity" id="alertscripts-bunkerquantity"></a>

```
import com.dataloy.ds.*;
import com.dataloy.*;
import java.math.*;
BunkerOrderLine bunkerOrderLineOld= null;
BunkerOrderLine bunkerOrderLineNew= null;
if(dlpObject instanceof BunkerOrderLine)
    bunkerOrderLineNew=  dlpObject;
if(oldDlpObject instanceof BunkerOrderLine)
    bunkerOrderLineOld=  oldDlpObject;
if( bunkerOrderLineOld!=null && bunkerOrderLineNew!=null && ((bunkerOrderLineOld.getBunkeredQuantity()==null && bunkerOrderLineNew.getBunkeredQuantity()!=null) || (bunkerOrderLineOld.getBunkeredQuantity()!=null && bunkerOrderLineNew.getBunkeredQuantity()==null) ||    !bunkerOrderLineNew.getBunkeredQuantity().equals(bunkerOrderLineOld.getBunkeredQuantity()))){
    mapResultsForMessage.put("?1",bunkerOrderLineNew.getBunkerType().getBunkerTypeDesc());
    mapResultsForMessage.put("?2",bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getVessel().getVesselName());
    if(bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getVoyageHeader()!= null && bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getVoyageHeader().getReferenceNo()!=null)
        mapResultsForMessage.put("?3",bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getVoyageHeader().getReferenceNo());
    else
        mapResultsForMessage.put("?3",bunkerOrderLineNew.getBunkerOrder().getPortCall().getVoyage().getKey());
     
    mapResultsForMessage.put("?4",bunkerOrderLineNew.getBunkerOrder().getPortCall().getPort().getPortName());
     
    Double value1= new BigDecimal(bunkerOrderLineNew.getBunkeredQuantity()).setScale(3, RoundingMode.HALF_UP).doubleValue();
    Double value2= new BigDecimal(bunkerOrderLineOld.getBunkeredQuantity()).setScale(3, RoundingMode.HALF_UP).doubleValue();
     
     
    String strValue1= value1.toString();
    String appValue1= strValue1.substring(strValue1.indexOf(".")+1, strValue1.length());
    while(appValue1.length()<3)
        appValue1= appValue1 +0;
    String finalValue1= strValue1.substring(0,strValue1.indexOf(".")+1)+appValue1;
     
     
    String strValue2= value2.toString();
    String appValue2= strValue2.substring(strValue2.indexOf(".")+1, strValue2.length());
    while(appValue2.length()<3)
        appValue2= appValue2 +0;
    String finalValue2= strValue2.substring(0,strValue2.indexOf(".")+1)+appValue2;
     
     
     
    mapResultsForMessage.put("?5",finalValue1 );
    mapResultsForMessage.put("?6",finalValue2 );
    return true;
}
else{
    return false;
}
```

### Bunker date <a href="#alertscripts-bunkerdate" id="alertscripts-bunkerdate"></a>

```
import com.dataloy.ds.*;
import com.dataloy.*;
import java.text.*;
BunkerOrder bunkerOrderOld= null;
BunkerOrder bunkerOrderNew= null;
if(dlpObject instanceof BunkerOrder)
    bunkerOrderNew=  dlpObject;
if(oldDlpObject instanceof BunkerOrder)
    bunkerOrderOld=  oldDlpObject;
if( bunkerOrderOld!=null && bunkerOrderNew!=null && ((bunkerOrderOld.getBunkeredDate()==null && bunkerOrderNew.getBunkeredDate()!=null) || (bunkerOrderOld.getBunkeredDate()!=null && bunkerOrderNew.getBunkeredDate()==null) ||    !bunkerOrderNew.getBunkeredDate().equals(bunkerOrderOld.getBunkeredDate()))){
    mapResultsForMessage.put("?1",bunkerOrderNew.getKey());
    mapResultsForMessage.put("?2",bunkerOrderNew.getPortCall().getVoyage().getVessel().getVesselName());
    if(bunkerOrderNew.getPortCall().getVoyage().getVoyageHeader()!= null && bunkerOrderNew.getPortCall().getVoyage().getVoyageHeader().getReferenceNo()!=null)
        mapResultsForMessage.put("?3",bunkerOrderNew.getPortCall().getVoyage().getVoyageHeader().getReferenceNo());
    else
        mapResultsForMessage.put("?3",bunkerOrderNew.getPortCall().getVoyage().getKey());
     
    mapResultsForMessage.put("?4",bunkerOrderNew.getPortCall().getPort().getPortName());
     
     
     SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy hh:mm");
     String date1 = DATE_FORMAT.format(bunkerOrderNew.getBunkeredDate());
     String date2 = DATE_FORMAT.format(bunkerOrderOld.getBunkeredDate());
     
    mapResultsForMessage.put("?5",date1);
    mapResultsForMessage.put("?6",date2);
    return true;
}
else{
    return false;
}
```

### Offhire start date <a href="#alertscripts-offhirestartdate" id="alertscripts-offhirestartdate"></a>

```
import com.dataloy.ds.*;
import com.dataloy.*;
import java.math.*;
import java.util.*;
 
        Offhire offhireInput= null;
        Voyage voyage= null;
        VoyageHeader voyageHeader= null;
        java.lang.System.out.println("---- offhire");
         
        if(dlpObject instanceof Voyage)
            voyage= dlpObject;
        if(dlpObject instanceof VoyageHeader)
            voyageHeader= dlpObject;
        if(dlpObject instanceof Offhire)
            offhireInput= dlpObject;
             
        List offhires= new ArrayList();
        if(offhireInput!=null) {
            offhires.add(offhireInput);
        }
        if(voyageHeader!=null){
            offhires= voyageHeader.getOffhires();
        }
        if(voyage!=null && voyage.getVoyageHeader()!=null){
            offhires= voyage.getVoyageHeader().getOffhires();
        }
        if(offhires!=null && !offhires.isEmpty()){     
            for (Offhire offhire : offhires) {     
                if(offhire!=null && offhire.getVoyageHeader()!=null){
                    java.lang.System.out.println("---- offhire="+offhire);
                    if(offhire.getOffhireStartDate() == null || offhire.getOffhireEndDate() == null || offhire.getVoyageHeader().getVoyageStartDate() == null){
                        return false;
                    }
                    int hcons = 60 * 60 * 1000;
                    int dcons = hcons * 24;
                     
                     
                    java.lang.System.out.println("---- offhire offhire.getTimezoneOffset()="+offhire.getTimezoneOffset());
                    java.lang.System.out.println("---- offhire offhire.getOffhireStartDate()="+offhire.getOffhireStartDate().getTime());
                    Double offStart = offhire.getOffhireStartDate().getTime() - offhire.getTimezoneOffset() * hcons;
                    java.lang.System.out.println("---- offhire offStart="+offStart);
                    Calendar triggerStart = Calendar.getInstance();
                    triggerStart.add(Calendar.YEAR, -1);
                     
                    if(offStart < triggerStart.getTimeInMillis()){
                        return false;
                    }
                     
                    Double offEnd = offhire.getOffhireEndDate().getTime() - offhire.getTimezoneOffset()  * hcons;
             
                    Double voyStart = offhire.getVoyageHeader().getVoyageStartDate().getTime() -( offhire.getVoyageHeader().getTimezoneOffset() * hcons);
                    Double voyEnd = voyStart + offhire.getVoyageHeader().getVoyage().getDaysTotal() * dcons;
             
                     
                    if(offStart < voyStart || offEnd > voyEnd){
                        mapResultsForMessage.put("?1",offhire.getVoyageHeader().getVoyage().getVessel().getVesselName());
                        mapResultsForMessage.put("?2",offhire.getVoyageHeader().getReferenceNo());
                        mapResultsForMessage.put("?3",offhire.getOffhireStartDate());
                        mapResultsForMessage.put("?4",offhire.getOffhireEndDate());
                        return true;
                    }
                }
                     
            }
        }
        else
            return false;
```

### Days in port updated  <a href="#alertscripts-daysinportupdated" id="alertscripts-daysinportupdated"></a>

```
import com.dataloy.ds.*;
import com.dataloy.*;
import java.math.*;
import java.util.*;
 
        PortCall portCall= null;
        PortCall portCallOld= null;
 
        if(dlpObject instanceof PortCall)
            portCall= dlpObject;
             
             
       if(oldDlpObject instanceof PortCall)
            portCallOld=  oldDlpObject;        
             
        if(portCall!=null &&  portCallOld!=null ) {
            java.lang.System.out.println("---- daysInPort IF");
             
             
            try{
             
                double diff= portCall.getDaysInPort() - portCallOld.getDaysInPort();
                if((diff < -1 || diff > 1)) {
                    mapResultsForMessage.put("?1",portCall.getPort().getPortName());
                    mapResultsForMessage.put("?2",portCall.getVoyage().getVessel().getVesselName());
                    mapResultsForMessage.put("?3",portCall.getVoyage().getVoyageHeader().getReferenceNo());
                    mapResultsForMessage.put("?4",portCall.getDaysInPort());
                    return true;
                }
            }
            catch(Exception e){
                java.lang.System.out.println("---- daysInPort Exception");
            }
        }
     
        return false;
```

### ETA outside laycan <a href="#alertscripts-etaoutsidelaycan" id="alertscripts-etaoutsidelaycan"></a>

```
import com.dataloy.ds.*;
import com.dataloy.*;
import java.math.*;
Cargo cargoOld= null;
Cargo cargoNew= null;
if(dlpObject instanceof Cargo)
    cargoNew=  dlpObject;
if(oldDlpObject instanceof Cargo)
    cargoOld=  oldDlpObject;
if( cargoOld!=null && cargoNew!=null && ((cargoOld.getLaycanMissedBy()==null && cargoNew.getLaycanMissedBy()!=null) || (cargoOld.getLaycanMissedBy()!=null && cargoNew.getLaycanMissedBy()==null) || !cargoNew.getLaycanMissedBy().equals(cargoOld.getLaycanMissedBy()))){
     
    String early = null;
     
    if(cargoNew.getLaycanMissedBy()==0){
        return false;
    }
 
    if(cargoNew.getLaycanMissedBy()<0){
        early = "early";
    }
 
    if(cargoNew.getLaycanMissedBy()>0){
        early = "late";
    }
     
    mapResultsForMessage.put("?1",cargoNew.getVoyage().getVessel().getVesselName());
    if(cargoNew.getVoyage().getVoyageHeader()!= null && cargoNew.getVoyage().getVoyageHeader().getReferenceNo()!=null)
        mapResultsForMessage.put("?4",cargoNew.getVoyage().getVoyageHeader().getReferenceNo());
    else
        mapResultsForMessage.put("?4",cargoNew.getVoyage().getKey());
 
    mapResultsForMessage.put("?2",early);
    mapResultsForMessage.put("?3",cargoNew.getCargoReference());
     
    Double value1= new BigDecimal(cargoNew.getLaycanMissedBy()).setScale(2, RoundingMode.HALF_UP).doubleValue();
     
    String strValue1= value1.toString();
    String appValue1= strValue1.substring(strValue1.indexOf(".")+1, strValue1.length());
    while(appValue1.length()<3)
        appValue1= appValue1 +0;
    String finalValue1= strValue1.substring(0,strValue1.indexOf(".")+1)+appValue1;
     
    mapResultsForMessage.put("?5",finalValue1 );
 
    return true;
}
else{
    return false;
}
```


# Script Body Guide (Groovy Java)

This page explains how to write the Script Body for an Alert Script. The script runs server-side and synchronously when the trigger event fires (Create / Update / Delete).

The script acts as a **boolean filter**:

* Return `true` → the event is significant and an alert should be generated
* Return `false` → suppress the alert for this event

***

### 1) Script Body rules (must-follow) <a href="#id-1-script-body-rules-must-follow" id="id-1-script-body-rules-must-follow"></a>

* **Groovy only**
* The Script Body is the **inside of a method** \
  ✅ Write statements directly \
  ❌ Do not add a class or method signature
* **Always return a boolean** on every path
* Prefer **early `return false`** for readability and safety

***

### 2) Runtime variables (available without declaration) <a href="#id-2-runtime-variables-available-without-declaration" id="id-2-runtime-variables-available-without-declaration"></a>

These are injected into the script context automatically:

#### **Core context**

* **`dlpObject` (Object)** Current state of the object that triggered the event.
* **`oldDlpObject` (Object)** Previous state of the object **only for UPDATE** events. Often `null` on INSERT, and may not match expected type.
* **`wsUser` (User)** The user/system account that performed the action. Useful for role-based suppression.

#### **Message output**

* **`mapResultsForMessage` (Map\<String, String>)** Placeholder map for template-based message text. Typical keys are `"?1"`, `"?2"` etc.
* **`mapMessageFromServer` (Map\<String, String>)** Full message override. Use key `"MSG"` to provide the message text.

***

### 3) Recommended structure (copy-paste mental model) <a href="#id-3-recommended-structure-copy-paste-mental-model" id="id-3-recommended-structure-copy-paste-mental-model"></a>

A clean script usually follows this flow:

1. **Imports** (only what you use)
2. **Type check + cast** `dlpObject` (and optionally `oldDlpObject`)
3. **Guard clauses** for nulls / wrong event shape
4. **Business logic** (status checks, threshold checks, role checks, etc.)
5. **Populate message values** (template placeholders or full message)
6. `return true`

***

### 4) Type check + casting (avoid ClassCastException) <a href="#id-4-type-check--casting-avoid-classcastexception" id="id-4-type-check--casting-avoid-classcastexception"></a>

`dlpObject` and `oldDlpObject` are generic `Object`, so type-check first.

```groovy
import com.dataloy.ds.Voyage
if (!(dlpObject instanceof Voyage)) 
    return false Voyage current = (Voyage) dlpObject
```

For old object (updates only):

```groovy
Voyage old = 
    (oldDlpObject instanceof Voyage)
     ? (Voyage) oldDlpObject
     : null
```

***

### 5) Null-Safety: Patterns and Best Practices <a href="#id-5-null-safety-patterns-dont-catch-npes-with-your-face" id="id-5-null-safety-patterns-dont-catch-npes-with-your-face"></a>

Assume linked objects can be null (headers, vessel, statuses, etc.). Use:

* **Guard clauses**
* Groovy **safe navigation** `?.`
* Null coalescing `?:`

```groovy
def vesselName = vessel?.vesselName
// vessel is null, so "Unknown vessel" is returned
def displayName = vesselName ?: "Unknown vessel"

def refNo = current?.voyageHeader?.referenceNo 
if (!refNo) 
    return false
```

***

### 6) Field access and status comparisons

#### Linked object navigation

```groovy
def statusCode = current?.voyageHeader?.voyageStatus?.statusTypeCode
```

#### Status fields

Compare **status codes**, not the status object:&#x20;

```groovy
if (!"OPR".equals(statusCode)) 
    return false
```

{% hint style="info" %}
Tip: `"LITERAL".equals(x)` is null-safe and avoids surprises.
{% endhint %}

***

### 7) Update/change detection (current vs old) <a href="#id-7-update-change-detection-current-vs-old" id="id-7-update-change-detection-current-vs-old"></a>

If your trigger is UPDATE and you only want alerts on change:

#### **Step-by-step pattern**

```groovy
if (old == null) return false // not an update or no previous state
```

#### **Null-safe comparisons**

Avoid calling `.equals()` on potentially null values.

```groovy
def newVal = current?.someField 
def oldVal = old?.someField
if (newVal == null || oldVal == null) return false 
if (newVal == oldVal) return false 
```

#### **Numeric thresholds (example)**

```groovy
import java.math.BigDecimal
BigDecimal newPnl = current?.voyageResult as BigDecimal 
BigDecimal oldPnl = old?.voyageResult as BigDecimal 
if (newPnl == null || oldPnl == null) return false
if ((newPnl - oldPnl).abs() <= 20000G) return false
```

***

### 8) Message building modes (CRITICAL – prevents misconfiguration)

There are **two valid combinations** between the Script Body and Message Configuration.

#### **Mode A — Build message in script = true**

Use this when the Script Body produces the full message text.**Requirements**

* `Build message in script = true`
* Script must set: `mapMessageFromServer["MSG"]`

{% code overflow="wrap" %}

```groovy
mapMessageFromServer.put("MSG", "Voyage PNL changed: " + current?.voyageHeader?.referenceNo) 
return true
```

{% endcode %}

#### **Mode B — Build message in script = false**

Use this when the server builds the message using a template string (`messageTxt`) and placeholder map.

**Requirements**

* `Build message in script = false`
* `messageTxt` must be provided (example: `"Hello ?1"`)
* Script sets: `mapResultsForMessage["?1"] = "World"`

Example configuration:

* `messageTxt = "Hello ?1"`

**Script:**

```groovy
mapResultsForMessage.put("?1", "World")
return true
```

#### **The broken combo**

**Don’t do this:**

* `mapResultsForMessage` + `Build message in script = true`

Reason: `Build message in script = true` expects `"MSG"` in `mapMessageFromServer`.

***

### 9) Guidance for generators / validation logic (recommended) <a href="#id-9-guidance-for-generators-validation-logic-recommended" id="id-9-guidance-for-generators-validation-logic-recommended"></a>

When auto-generating alert script configs, set `Build message in script` using this rule:

1. If Script Body contains `mapMessageFromServer` → set **true**
2. Else if Script Body contains `mapResultsForMessage` AND `messageTxt` is set → set **false**
3. Else → fail validation or require the missing pieces (recommended)

This prevents “alerts firing with empty messages” situations.

***

### 10) Optional: fetching related data (advanced) <a href="#id-10-optional-fetching-related-data-advanced" id="id-10-optional-fetching-related-data-advanced"></a>

Sometimes the needed data is not reachable from `dlpObject` (link not loaded / not present). You can query the database using:

```groovy
com.dataloy.platform.query.DlpObjectSelect
```

{% hint style="warning" %}
Method details can vary by version and are not fully documented. Use known examples as reference and test carefully.
{% endhint %}

***

### 11) Troubleshooting <a href="#id-11-troubleshooting" id="id-11-troubleshooting"></a>

#### **Logging**

Print debug information to application logs:

```groovy
java.lang.System.out.println("---- newPnl: " + newPnl)
```

#### **Return-path sanity**

If alerts don’t fire:

* confirm type-check isn’t rejecting
* confirm `oldDlpObject` isn’t null when you expect update logic
* confirm [message building](https://app.gitbook.com/o/-LhoT2vqihl0pYiCeolt/s/7R7IFboJW2JabvnivFfc/~/edit/~/changes/32/voyage-management-system/step-by-step-guides/alerts/alert-scripts/script-body-groovy-detailed-guide#id-8-message-building-modes-critical-prevents-misconfiguration) is valid

***

### 12) Full example (safe, readable, and template-based) <a href="#id-12-full-example-safe-readable-and-template-based" id="id-12-full-example-safe-readable-and-template-based"></a>

Config:

* `Build message in script = false`
* `messageTxt = "Voyage ?1 PNL changed to ?2"`

Script:

```groovy
import com.dataloy.ds.Voyage 
import java.math.BigDecimal

if (!(dlpObject instanceof Voyage)) return false 
Voyage current = (Voyage) dlpObject

Voyage old = (oldDlpObject instanceof Voyage) ? (Voyage) oldDlpObject : null 
if (old == null) return false

BigDecimal newPnl = current?.voyageResult as BigDecimal 
BigDecimal oldPnl = old?.voyageResult as BigDecimal 
if (newPnl == null || oldPnl == null) return false

if ((newPnl - oldPnl).abs() <= 20000G) return false

mapResultsForMessage.put("?1", current?.voyageHeader?.referenceNo ?: "") 
mapResultsForMessage.put("?2", String.valueOf(newPnl))
return true
```


# Websockets

Build interactive HTML 5 application using Dataloy Websockets.

It is possible to open a Websocket to get notified when there are changes in Dataloy data model.

The concept is very similar to Webhooks, it is possible open a socket to be notified for Creation, Update and Deletion of any of object type of the data model.

The endpoint syntax is:

* **ws\://{url}/ws/rest/WebSocketObjectSubscription/{objectType}/{eventType}/{key}/{token}**

The JSON pushed will have the same structure of the one pushed by Webhooks.

It is possible to customize the JSON sent from the Server to the Client using [*Adjust Number of Fields to be Returned from a Request*](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414751/Adjust+Number+of+Fields+to+be+Returned+from+a+Request)*.*

*(The JSON fields can be sent through the open Websocket by the Client to the Server)*

(To get back to the standard fields list a empty JSON ( {} ) can be sent from the client to the server)

It is possible to open a Websocket linked to an Alert Script to be notified when the script is fired and returns true.

The endpoint to use is:

* **ws\://{url}/ws/rest/WebSocketAlertScript/{scriptCode}/{token}**

Passing the script code.


# Bulk Deletion

It is possible to delete multiple objects, of a given resource, sending as URL parameters the list of keys:

* DELETE: <mark style="color:blue;">http\://{host}/ws/rest/{Resource name}/delete?key={key 1}\&key={key 2}\&key={key 3}...</mark>

All the objects will be deleted in the same transaction

Furthermore, Bulk Delete supports object resequencing. This is useful in cases where the order of the objects is crucial and has to be precise, but also it's required to delete several objects at once. For instance, BunkerCategories on Vessel are following strict priority order, thus upon deletion, the order should be re-aligned.

Re-sequencing is active ONLY when at least a valid 'resequenceBy' string is passed.

* DELETE:  <mark style="color:blue;">http\://{host}/ws/rest/{ResourceName}/delete?resequenceBy={</mark>*<mark style="color:blue;">sequence field</mark>*<mark style="color:blue;">}\&parentProperty={</mark>*<mark style="color:blue;">parent property</mark>*<mark style="color:blue;">}\&key={key1}\&key={key2}...</mark>
  * *Sequence field* - is a string identifying the 'sequence property'. For example, it would be portCallSequence for ResourceName = PortCall.
  * *Parent property* - Optionally filter by the parent group using a string specifying the parent field. For example, if ResourceName is PortCall, pass the field ownedByVoyage to re-sequence only PortCalls belonging to the same voyage.&#x20;


# Copy objects

It is possible copy any object of any resource with the following endpoint:

* POST: [http://{host}/ws/rest/{Resource name}/copy/{](http://localhost:8080/ws/rest/Cargo/copy/213496782)key}

It will create a new object in the data model, copying also the sub-objects, and will return it as response.

&#x20;

It is possible override attributes passing a JSON in the body (passing an attribute with null value will have no effect. Only simple types in the first level of the JSON will be used to override).

&#x20;

It is possible copy multiple objects, of a give resource, sending as URL parameters the list of keys:

* POST: [http://{host}/ws/rest/{Resource name}/copy?](http://localhost:8080/ws/rest/Cargo/copy/213496782)key={key 1}\&key={key 2}\&key={key 3}...

it will create a new object for all the specified keys and returns am array of the created objects.


# OR and AND operators in API queries

Is possible to use both OR and AND operators in API queries. The two new operators syntax are:

* (OR)
* (AND)

Set of filters can be separated by OR and AND operators, the filters within a single set of filter will be put in AND.

Some examples:

Cargo?filter=charterer.businessPartnerType.businessPartnerType(EQ)&[**filter=(OR)**](http://localhost:8080/ws/rest/CargoPort?filter=cargo.charterer\(IN\)\(20006011\)\&filter=port.portName\(IN\)\(OSLO\)\&filter=cargo.voyage.voyageStatus\(EQ\)%20\&filter=\(OR\)\&filter=cargo.charterer\(IN\)\(20006011\)\&filter=port.portName\(IN\)\(BERGEN\)\&filter=cargo.voyage.voyageStatus\(EQ\)%20)\&filter=weight(GT)400000

[CargoPort?filter=cargo.charterer(IN)(20006011)\&filter=port.portName(IN)(OSLO)&**filter=(OR)**\&filter=cargo.charterer(IN)(20006011)\&filter=port.portName(IN)(BERGEN)](http://localhost:8080/ws/rest/CargoPort?filter=cargo.charterer\(IN\)\(20006011\)\&filter=port.portName\(IN\)\(OSLO\)\&filter=cargo.voyage.voyageStatus\(EQ\)%20\&filter=\(OR\)\&filter=cargo.charterer\(IN\)\(20006011\)\&filter=port.portName\(IN\)\(BERGEN\)\&filter=cargo.voyage.voyageStatus\(EQ\)%20)&#x20;

CargoPort?filter=cargo.charterer.key(EQ)1001845\&filter=cargo.voyage.voyageStatus(EQ)%20\&filter=port.portName(IN)(OSLO)\&filter=reasonForCall.reasonForCall(EQ)L&**filter=(OR)**\&filter=cargo.voyage.voyageStatus(EQ)%20\&filter=port.portName(IN)(GAETA)\&filter=reasonForCall.reasonForCall(EQ)D&**filter=(OR)**\&filter=reasonForCall.reasonForCall(EQ)E

&#x20;

Limitations:

* It is not possible use calculated fields with AND and/or OR.&#x20;
* Parenthesis are not supported&#x20;


# Sub queries

API 5.21 supports sub-queries during any API query.

The syntax is:

* filter=attributeName(OPERATOR)**{**&#x52;esourceName.attributeNam&#x65;**\[**&#x66;ilter\_&#x31;**]**,**\[**&#x66;ilter\_&#x32;**]**,**\[**&#x66;ilter\_&#x6E;**]}**

en-capsuling sub-queries between {} and the filters inside the sub-queries as list inside \[ ]

Here an example to get the ongoing cargoes of a list of business partners:

[http://dataloy.com/ws/rest/Cargo?filter=charterer.businessPartnerCode(IN)(133105,105882,123125,136200)\&filter=key(IN)({Cargo.key\[cargoPorts.portCall.eventLogs.event.eventCode(EQ)ARR](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/1556250625/Sub+queries#)]\[cargoPorts.portCall.eventLogs.eventLogDate(GT)2020-06-18T17:02:21]\[cargoPorts.cargoPortSequence(EQ)1],\[cargoPorts.reasonForCall.reasonForCall(EQ)D]})\&filter=key(IN)({Cargo.key\[cargoPorts.portCall.eventLogs.event.eventCode(EQ)DEP]\[cargoPorts.portCall.eventLogs.eventLogDate(LT)2020-06-18T17:02:21]\[cargoPorts.cargoPortSequence(EQ)1],\[cargoPorts.reasonForCall.reasonForCall(EQ)L]})

&#x20;

[http://dataloy.com/ws/rest/Cargo?filter=charterer.businessPartnerCode(IN)(133105,105882,123125,136200)\&filter=key(IN)(%7BCargo.key\[cargoPorts.portCall.eventLogs.event.eventCode(EQ)ARR](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/1556250625/Sub+queries#)]\[cargoPorts.portCall.eventLogs.eventLogDate(GT)2020-06-18T17:02:21]\[cargoPorts.cargoPortSequence(EQ)1],\[cargoPorts.reasonForCall.reasonForCall(EQ)D]%7D)\&filter=key(IN)(%7BCargo.key\[cargoPorts.portCall.eventLogs.event.eventCode(EQ)DEP]\[cargoPorts.portCall.eventLogs.eventLogDate(LT)2020-06-18T17:02:21]\[cargoPorts.cargoPortSequence(EQ)1],\[cargoPorts.reasonForCall.reasonForCall(EQ)L]%7D)

**The character { must be encoded with %7B and } with %7D**


# XML Transformation

API 5.24 offers support for XML transformations for any of the resource of the data model.

Using XSLT 3.0 is possible inject XSL strings to any GET request to translate the default JSON response in a XML string based on the XSL in input.

To achieve this the URLs to use are

* /ws/rest/{ResourceName}/xml
* /ws/rest/{ResourceName}/xml/{key}

the XSL must be set as HTTP header parameter with the name **xsl.**

Example of Cargo transformation:

XSL:

```
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" xpath-default-namespace="http://www.w3.org/2005/xpath-functions">
   <xsl:output indent="yes" />
   <xsl:strip-space elements="*" />
   <xsl:param name="json" />
   <xsl:mode on-no-match="deep-skip" />
   <xsl:template name="init">
      <xsl:apply-templates select="json-to-xml($json)" />
   </xsl:template>
   <xsl:template match="/array">
      <Cargos>
         <xsl:apply-templates />
      </Cargos>
   </xsl:template>
   <xsl:template match="/array/map | /map">
      <Cargo>
         <xsl:apply-templates />
      </Cargo>
   </xsl:template>
   <xsl:template match="*[@key='voyage']">
      <IsTc>
         <xsl:value-of select="*[@key='isTc']" />
      </IsTc>
      <VesselCode>
         <xsl:value-of select="*[@key='vessel']/*[@key='vesselCodes'][1]/*/*[@key='vesselCode']" />
      </VesselCode>
      <VesselName>
         <xsl:value-of select="*[@key='vessel']/*[@key='vesselName']" />
      </VesselName>
   </xsl:template>
   <xsl:template match="*[@key='commodity']">
      <CommodityName>
         <xsl:value-of select="*[@key='commodityName']" />
      </CommodityName>
   </xsl:template>
   <xsl:template match="*[@key='cargoPorts']">
      <xsl:apply-templates select="*/*" />
   </xsl:template>
   <xsl:template match="*[@key='portCall']">
      <xsl:variable name="reasonForCall" select="*[@key='reasonForCall']/*[@key='reasonForCall']" />
      <xsl:variable name="name" select="*[@key='port']/*[@key='portName']" />
      <xsl:if test="$reasonForCall = 'L' ">
         <LoadPort>
            <xsl:value-of select="$name" />
         </LoadPort>
         <LoadPortArrival>
            <xsl:apply-templates select="*/*" />
         </LoadPortArrival>
      </xsl:if>
      <xsl:if test="$reasonForCall = 'D' ">
         <DischargePort>
            <xsl:value-of select="$name" />
         </DischargePort>
         <DischargePortArrival>
            <xsl:apply-templates select="*/*" />
         </DischargePortArrival>
      </xsl:if>
   </xsl:template>
   <xsl:template match="*[@key='eventLogs']/*">
      <xsl:variable name="code" select="*[@key='event']/*[@key='eventCode'][text() = 'ARR']" />
      <xsl:if test="$code">
         <xsl:value-of select="*[@key='eventLogDate']" />
      </xsl:if>
   </xsl:template>
</xsl:stylesheet>
```

URL: <http://platform-dev.dataloy.com/ws/rest/Cargo/xml/1225540>

Output:

```
<?xml version="1.0" encoding="UTF-8"?>
<Cargo>
    <CommodityName>FERTILIZER</CommodityName>
    <LoadPort>AMSTERDAM</LoadPort>
    <LoadPortArrival>2006-06-14T12:17:00</LoadPortArrival>
    <DischargePort>LIDKOPING</DischargePort>
    <DischargePortArrival>2006-06-17T19:53:00</DischargePortArrival>
    <IsTc>false</IsTc>
    <VesselCode>FETR</VesselCode>
    <VesselName>FEHN TRADER</VesselName>
</Cargo>
```


# Bulk Update

The Bulk Update can be used to any object of the data model.

The endpoint to use is:

* PUT: [http://{host}/ws/rest/{Resource name}/bulkUpdate?](http://localhost:8080/ws/rest/Cargo/copy/213496782)key={key 1}\&key={key 2}\&key={key 3}...

passing ,to the specified resource, a list of key that have to be changed by the input body.

The endpoint returns 204 with no content if succeeded.

Bulk Update can also be used with [Expressions](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/2146435073) :

For example

[http://platform-dev.dataloy.com/ws/rest/Voyage/bulkUpdate?expression=ballastPort.isCanal=true](http://platform-dev.dataloy.com/ws/rest/%7BObjectName%7D/bulkUpdate?expression=ballastPort.isCanal=true)


# Aggregate Functions

### Overview

The Aggregate Functions API allows you to perform statistical calculations (average, sum, minimum, maximum, count, list) on numeric fields in list responses. This enables data analysis and trend identification without making additional API calls.

### Endpoint

```
POST /ws/rest/{Resource}/aggregate
```

### Request Parameters

#### Query Parameters

Our standard filtering and expression functionality can be used to filter data before applying aggregate functions.

#### Request Body

The request body must contain a JSON object with a `functions` array that specifies which aggregate functions to perform on which fields.

```json
{
  "functions": [
    {
      "type": "string",  // Aggregate function type
      "field": "string"  // Field to aggregate
    }
  ]
}
```

**Supported Aggregate Function Types**

| Type  | Description                          | Applicable Fields   |
| ----- | ------------------------------------ | ------------------- |
| avg   | Calculates the average value         | Numeric fields only |
| sum   | Calculates the sum of all values     | Numeric fields only |
| min   | Finds the minimum value              | Numeric fields only |
| max   | Finds the maximum value              | Numeric fields only |
| count | Counts the number of non-null values | Any field           |
| list  | Returns a list of all unique values  | Any field           |

**Special Field Values**

* For `count` function, you can use `*` as the field value to count all records.

### Response

The API returns a JSON object with a `results` array containing the computed aggregate values.

```json
{
  "results": [
    {
      "type": "string",    // The aggregate function type
      "field": "string",   // The field that was aggregated
      "value": any         // The result of the aggregate function
    }
  ]
}
```

The `value` field will contain:

* A numeric value for `avg`, `sum`, `min`, `max`, and `count` functions
* An array of values for the `list` function

### Examples

#### Calculate Average of a Numeric Field

**Request:**

```
POST /ws/rest/VoyageHeader/aggregate
```

**Request Body:**

```json
{
  "functions": [
    {
      "type": "avg",
      "field": "doRobVoyageStart"
    }
  ]
}
```

**Response:**

```json
{
  "results": [
    {
      "type": "avg",
      "field": "doRobVoyageStart",
      "value": 125.4
    }
  ]
}
```

#### Calculate Multiple Aggregates with Filter or Expression

**Request:**

```
POST /ws/rest/VoyageHeader/aggregate?filter=voyage.isTc(EQ)true

POST /ws/rest/VoyageHeader/aggregate?expression=voyage.isTc=true
```

**Request Body:**

```json
{
  "functions": [
    {
      "type": "sum",
      "field": "foRobVoyageStart"
    },
    {
      "type": "min",
      "field": "foPriceVoyageStart"
    },
    {
      "type": "list",
      "field": "referenceNo"
    }
  ]
}
```

**Response:**

```json
{
  "results": [
    {
      "type": "sum",
      "field": "foRobVoyageStart",
      "value": 1250.6
    },
    {
      "type": "min",
      "field": "foPriceVoyageStart",
      "value": 450.75
    },
    {
      "type": "list",
      "field": "referenceNo",
      "value": ["V2023-001", "V2023-002", "V2023-003"]
    }
  ]
}
```

#### Count All Records

**Request:**

```
POST /ws/rest/VoyageHeader/aggregate
```

**Request Body:**

```json
{
  "functions": [
    {
      "type": "count",
      "field": "*"
    }
  ]
}
```

**Response:**

```json
{
  "results": [
    {
      "type": "count",
      "field": "*",
      "value": 123
    }
  ]
}
```

### Error Handling

The API validates the request and returns appropriate error messages:

* If an invalid function type is specified, the API returns HTTP 400.
* If an invalid field is specified, the API returns HTTP 400.
* If an incompatible function type is used with a field (e.g., "avg" on a text field), the API returns HTTP 400.

#### Error Response Example

```json
{
  "statusCode": 400,
  "message": "Cannot apply 'avg' function to field 'testText'. Only numeric fields are supported for this operation."
}
```

### Limitations

* Date aggregation functions (min/max) are not supported and will return a 400 error.
* Text fields cannot be used with numeric aggregate functions (avg, sum, min, max) and will return a 400 error.
* All fields must exist in the data model, or the request will be rejected.


# Bulk Update Increment

Bulk Update Increment allows you to update multiple fields on multiple objects at once. With this endpoint multiple objects values can be set individually in bulk.

Use this endpoint to update multiple objects in one call by sending a JSON array of object keys and their new field values.

The endpoint to use is:

```
http://{host}/ws/rest/{ResourceName}/bulkUpdateIncrement
```

Passing, to the specified resource, a JSON array of entries, each containing:

* `key`: the primary key of the object
* one or more field names with the new value to set

Example payload:

```json
[
  { 
  "key": 77441913, 
  "foBallast": 10, "foLoaded": 15 
  },
  { 
    "key": 77443840,
    "foBallast": 12, "foLoaded": 20
  }
]
```

* Object `77441913` will have its `foBallast` field set to 10 and its `foLoaded` field set to 15.
* CommentShare feedback on the editorObject `77443840` will have its `foBallast` field set to 12 and its `foLoaded` field set to 20.

{% hint style="info" %}
**Note:** Each entry must include a `key` and at least one other field to update.
{% endhint %}


# API Request Expressions

{% hint style="info" %}
This guide covers API Request Expression which is not the same as Webhook Expressions. If you are looking for Webhook Expressions you will find that in the Webhooks section.
{% endhint %}

With expressions is possible to use logical syntax, like we do in SQL, to filter any resource response.

One easy example could be (assuming that we are querying Voyage endpoint):

* **voyageResult > 1000 and voyageHeader.voyageStatus.statusTypeCode= 'FIN'**

Bit more complex one could be:

* **vessel.vesselName ='Borg 1' and (voyageHeader.operator = 999999 or voyageHeader.charteringResponsible = 999999 or voyageHeader.accountantResponsible= 999999)**

That introduce a completely new possibility, the usage of **parenthesis.**

It is possible to have any level of nested parenthesis:

* **(voyageHeader.operator != 999999 and ((voyageResult > 10000 and voyageHeader.voyageStatus.statusTypeCode= 'FIN') or (voyageResult < 10000 and voyageHeader.voyageStatus.statusTypeCode= 'NOM')))**

Support for **between** operator:

* **voyageResult between 1000 and 2000**

The dates in the expression must be preceded by the character **$**

* **voyageHeader.voyageStartDate > $2020-12-29T17:02:21**

To get all the voyages of the master scenario:

* **(voyageHeader.voyageStartDate>=$2021-01-14T17:02:21 and fleetPlanVoyages.fleetPlan.fleetPlanCode='MASTER') or (scenarios.scenarioCode='MASTER' and voyageHeader.voyageStatus.statusTypeCode= 'SCU')**

Supported Operators (all the operator are case sensitive):

| **Operator**       | **Description**       | **Note**                                                            |
| ------------------ | --------------------- | ------------------------------------------------------------------- |
| =                  | equal to              | ​                                                                   |
| !=                 | not equal to          | ​                                                                   |
| >                  | greater than          | ​                                                                   |
| >=                 | greater than equal to | ​                                                                   |
| <                  | less than             | ​                                                                   |
| <=                 | less than equal to    | ​                                                                   |
| between            | between               | ​                                                                   |
| not between        | not between           | ​                                                                   |
| in                 | in                    | ​                                                                   |
| not in             | not in                | ​                                                                   |
| like               | like                  | % must be encode with %25                                           |
| not like           | not like              | ​                                                                   |
| likeIgnoreCase     | like ignore case      | ​                                                                   |
| not likeIgnoreCase | not like ignore case  | ​                                                                   |
| !                  | negation              | on Vessel resource: ! (hasGrabsOnboard = false and iceClass = null) |

The expressions can be used in any resource of the data model.

The expression can be passed or through the URL query parameter called **expression (**&#x72;emember to encod&#x65;**):**

* ws/rest/Voyage?**expression**=vessel.vesselName='Borg 1' or voyageResult between 10 and 10000

or through the HTTP header parameter called **expression.**

The expression can be used in combination with sorting and pagination through URL query parameters.

Calculated fields cannot be used within the expressions.


# Dataloy VMS API

**The&#x20;*****Dataloy VMS API***  documentation is intended as the main source of information and answers to queries and issues regarding integration with Dataloy VMS. It provides an overview of how integration with Dataloy VMS may be accomplished and detailed information about each type of integration.&#x20;

High focus has been placed on quality of standard, substance and user-friendliness. The API knowledge base is kept continuously up-to-date. There is also a questions & answers section and a troubleshooting article section..<br>

To search/navigate either click the links below or use the left-hand navigation panel to search by keyword, category or hierarchy.

*API:*

* [What is it?](/api-release-8.25/dataloy-rest-api/what-is-it)
* [Authentication / Authorization](/api-release-8.25/dataloy-rest-api/authentication-authorization)
* [Getting Started](/api-release-8.25/dataloy-rest-api/getting-started)
* [Data Model](/api-release-8.25/dataloy-rest-api/data-model)
* [Filtering](/api-release-8.25/dataloy-rest-api/filtering)
* [Sorting](/api-release-8.25/dataloy-rest-api/sorting)
* [Pagination](/api-release-8.25/dataloy-rest-api/pagination)
* [Adjust Number of Fields to be Returned from a Request](/api-release-8.25/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request)
* [Webhooks](/api-release-8.25/dataloy-rest-api/webhooks)
* [Master Data Objects](/api-release-8.25/dataloy-rest-api/master-data-objects)

[*User Guides*](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414844/User+Guides)*:*

* [Accounting Integration API](/api-release-8.25/user-guides/accounting-integration-api)
* [Schedule API](/api-release-8.25/user-guides/schedule-api)
* [Bunker Order Integration API](/api-release-8.25/user-guides/bunker-order-integration-api)
* [Service Order Integration API](/api-release-8.25/user-guides/service-order-integration-api)
* [Vessel Report](/api-release-8.25/user-guides/vessel-report)
* [Consumptions API](/api-release-8.25/user-guides/bunker-consumption-api)
* [Market Index API](/api-release-8.25/user-guides/market-index-integration-api)

*Questions & Answers, Troubleshooting Articles:*<br>

* [Questions & Answers API](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414741)
* [Troubleshooting Articles API](https://dataloy-cloud.atlassian.net/wiki/pages/createpage.action?spaceKey=VMSINT\&title=Troubleshooting%20Articles%20API\&linkCreation=true\&fromPageId=923414838)


# What is it?

**The Dataloy REST API** allows for the retrieval, updating and entry of all data in Dataloy VMS.&#x20;

As the Dataloy API is based on REST principles it is easy to write and simple to use when testing applications.

A typical company uses many applications, of which many or most are not designed to work with one another. Integrating separate, but related, applications help organizations achieve greater levels of operational consistency, efficiency and quality. Integration can be considered if a system generates/consumes data relevant to Dataloy VMS and/or can share data with the VMS.&#x20;


# Authentication / Authorization

Authentication and authorization is done through OAuth 2.

To get access to the protected resources OAuth 2.0 uses Access Tokens. An Access Token is a string representing the granted permissions.

To access to Dataloy API, you must request an Access Token.&#x20;

To obtain an access token you  need to do a POST request, to  the provided URL, passing the client id and client secret in the payload

Example of POST payload to token URL

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
"client_id":"G99j845dM4MtckQlKt8E6o......",
"client_secret":"-mMElVOMzvht2SyQPfVh-WIaPCbOxRdWN5YngBxtBKybQmli-....",
"audience":"https://dataloy.internal",
"grant_type":"client_credentials"
}
</code></pre></td></tr></tbody></table>

#### Parameters

| Parameter Name  | Description                                                                                                                                                    |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `grant_type`    | Set this to "client\_credentials".                                                                                                                             |
| `client_id`     | Your M2M Client ID.                                                                                                                                            |
| `client_secret` | Your M2M Client Secret.                                                                                                                                        |
| `audience`      | The audience for the token, which is your API. For production environments use "<https://dataloy>". For  test and DEV environments use "<https://dataloy.dev>" |
|                 |                                                                                                                                                                |

#### Response

If all goes well, you'll receive an HTTP 200 response with a payload containing `access_token`, `token_type`, and `expires_in` values:

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1....................fXClgZe2pFQBxPqARz9xfWlrFnc1El34ZPyRLoGlLIJLiE0NvOA1JLWycXCNo9N7AenAKEbj-gb2eW4TnpAiidDRmMV3m36UCuRAxWdVcvsRaJxXcquf79wAgEoEKriJklCxwKOnOyngbTZ2vDNim0nrw6-W0NOjRARkkY_w-188dY829z_urjsWuCC7TOMwfrQDLL2h72L2UrqlyL0hHMGQesau6h8KUsGg3EIoWPQ-Pf6o2CNCtGyr7DNuuLpCw9HqXiz5v-RIvKLBoaRMAAJJqBeXvpPvOcyicBlalcTWB5NMCe6Ldi9xqFmwjhO1CAtIk9QUa8wsOcXxg",
"expires_in": 86400,
"token_type": "Bearer"
}
</code></pre></td></tr></tbody></table>

#### Call API endpoint

To call an API endpoint you must pass the retrieved Access Token as a Bearer token in the Authorization header of your HTTP request.

\
curl https\://{URL}/ws/rest/{Resource}-H "Authorization: Bearer eyJ.........qLbZQ"

When an endpoint is invoked with an expired token the server sends a HTTP 401 response with the following payload:

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
    "statusCode": 401,
    "statusText": "Unauthorized",
    "message": "Token expired.",
    "date": "2019-11-13T06:26:01",
    "statusFamily": "CLIENT_ERROR",
    "method": "GET",
    "uri": "http://platform-dev.dataloy.com/ws/rest/Cargo?filter=subCargos.freight%28GTE%292500000"
</code></pre></td></tr></tbody></table>

The client should not ask for a new token for each call but use the same token as long as it is valid.


# Getting Started

**Getting Started with Dataloy REST API** (*Application Programming Interface*) provides an introduction to the Dataloy API directed towards developers and IT-personnel. Basics, such as how to obtain, submit and modify data, are explained.

Dataloy’s API uses a REST interface over HTTP/HTTPS. The currently supported payload is application/JSON.

## **To Get Started**

Follow the below steps - they will return USD currency from Dataloy VMS (illustrating that the API works properly):

```
https://[ip]:[port]/ws/rest/Currency?filter=currencyCode(EQ)USD
```

## **Request Format**

For **POST** and **PUT requests,** the payload *must* be **JSON** and the **Content-Type** be set to **application/JSON**.

**Base URL**

The base URL is **customer-specific**. To obtain the IP-address and port for the specific API installation, please **contact** [**Dataloy**](mailto:support@dataloy.com).

```
https://[ip]:[port]/ws/rest
```

\
**IMPORTANT**: All URLs in this documentation is relative to the root URL stated below. The HTTP method will be written in front of the relative URL:\
***Note**: The root URL should NOT be hardcoded in your application to allow it to run against multiple servers. The "/ws/rest" part may also change in the future.*

```
GET /Cargo/123456
```

Example:\
\
*When the documentation refers to /Cargo, the full URL is https\://\[ip]:\[port]/ws/rest/Cargo.*<br>

## **General URL Structure**

Resources *(for example: Voyage, Document, ExchnangeRate)*, have a similar general URL structure.\
\
Example:\
\
*In the table below* "/Entity" *represents the name of an entity type like* "/Cargo" *or* "/Voyage"*.*

| Relative URL | Methods          | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ------------ | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|              | GET, POST        | <ul><li>Represents the collection of entities of the given type.</li><li>GET will return a filterable array of entities of that type.</li><li>These entities will be "minimized" and sometimes contain only the "key" and "self" properties.</li><li>POST will insert a new entity of that type into the collection.</li></ul>                                                                                                                                                                                                                                                                                                               |
|              | GET, PUT, DELETE | <ul><li>Represents a single entity of the given type, identified by "key".</li><li>GET will return the full representation of that entity.</li><li>PUT will update the given entity. A PUT request may contain only the changed properties, and will return the full object after the change. From API version 3, PUT will also update Sub-objects, previous versions are limited to object by object updating. For API versions prior to version 3, Sub-objects should <strong>NOT</strong> be included in PUT requests.</li><li>DELETE will return 200 OK and an empty body when successful. Not all entities can be be deleted.</li></ul> |

## **Exception Handling**

Dataloy's API return HTTP status codes in the HTTP header and provides additional information in the body in **JSON format**.

{% hint style="info" %}
This example has been updated for API version 2.0.0 using date format yyyy-dd-MMThh:mi:ss to conform ISO 8601, versions prior to 2.0.0 has the following date format: yyyy-dd-MM hh:mi:ss
{% endhint %}

```
{
    "statusCode": 400,
    "statusText": "Bad Request",
    "message": "Missing field(s) in json body. All fields are required.",
    "date": "2013-02-05T09:49:52",
    "statusFamily": null,
    "method": null,
    "uri": null
}
```

\
**Retrieve Data from Dataloy API**
----------------------------------

Information is retrieved by using a **GET request on a URL**. Each resource has it’s own URL. The API also supports searching resource specific parameters.

GET request on a URL:

Example: \
\
*The following GET request on example URL will return the document with ID 2729538.*

| `https://server.com/ws/rest/Document/2729538` |
| --------------------------------------------- |

\
**Filtering Data**
------------------

Dataloy API is equipped with a strong generic filtering functionality. It is able to filter on almost any field visible in the API and filtering any resources returning an array of objects (see [Filtering](/api-release-8.25/dataloy-rest-api/filtering)). <br>

## **Modifying Data Through Dataloy API (PUT)**

Use **PUT** to modify data through the API. Specify the **URL of a resource** and send the content to be modified in the **body of the HTTP call**. A successful PUT will return the same body as a GET on that resource. Excluded properties will be **ignored**. Excluded array elements will be **removed**. From API version 3, PUT will also update Sub-objects, previous versions are limited to object by object updating. For API versions prior to version 3, Sub-objects should **NOT** be included in PUT requests.

Examples:&#x20;

\
**Updating** properties for a **main object**. In this case VoyageHeader

```
{
   "doProfitLoss": 1.1,
   "tradeVoyageNo": 2345,
   "isBudget": true,
   "voyageStartDate": "2017-03-01T01:58:00",
   "referenceNo": "12341"
}
```

**Updating** properties for a **sub-object**. In this case, Voyage is the main object and Cargo is the sub-object

```
{
    "cargos": [
        {
            "bookedQuantity": 10000        
        }
    ]
}
```

**Insert** an **array element**

```
{
  "remarks": [
      {
           "remarkTitle": "A Test remark title 1"
      }
   ]
}
```

**Update** an **array element** by including the key for the array element. The key is generated by the API when inserting a new element.

```
{
  "remarks": [
      {
           "key": 234581088,
           "remarkTitle": "A Test remark title 1 Updated"
      }
   ]
}
```

**Insert** a second **array element** by including the key for the first array element. Then add a second array element without a key.

```
{
  "remarks": [
      {
           "key": 234581088,
           "remarkTitle": "A Test remark title 1 Updated"
      },
       {
           "remarkTitle": "A Test remark title 2"
      }
   ]
}
```

**Remove** an **array element**. When having two elements in an array, you can remove one of them by removing the element in the PUT body

```
{
  "remarks": [
      {
           "key": 234581088
      }
   ]
}
```

## **Sub-objects**

Inserting (POST) or updating (PUT) references to sub-objects can be done in different ways:\
*(All the examples below is using VoyageHeader as a main object and the specified company will be linked to the VoyageHeader.)*

*Specify the **key** to an existing sub-object*

All existing objects has a key that is created by Dataloy API. This can be used for linking an existing object to another object.

```
{   "company":4601029}
```

*Specify the **code** to an existing sub-object*

[A lot of the objects in Dataloy API has an unique code that can be used for identifying an object.](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414749/List+of+API+Resources+having+Code+Properties) This code can also be used for linking an existing object to another object.

```
{   "company": "09"}
```

*Specify the **sub-object***

Another option for linking a sub-object is to provide the object to be linked.

```
{   "company": {       "key": 163348582   }}
```

*Create a **new object***

The last option is to create a new sub-object and link it to a object in the same request. When excluding the key property a new object will be created.

```
{
   "company": {       
       "companyCode": "1234",
       "companyName": "Test Company"
   }
}
```

## **Inserting Data Through Dataloy API (POST)**

Send a **POST request** to a base resource URL with a body conforming with the minimum requirements of that resource.

Example: \
\
*POST request URL:*&#x20;

| `https://ip:port/ws/rest/Document` |
| ---------------------------------- |

{% hint style="info" %}
All the dates are in the format **yyyy-dd-MMThh:mi:ss** to conform ISO 8601
{% endhint %}

&#x20;**Body of Document HTTP POST**

```
{
    "documentAmount": 0.0,
    "companyCurrencyAmount": 0.0,
    "sourceCurrencyAmount": 0.0,
    "documentDate": "2013-04-04T00:00:00",
    "documentType": "PMI",
    "invoicingStatus": "POS",
    "documentNo": "XXXXXX",
    "company": 10001,
    "documentCurrency": "USD",
    "documentText": "text here",
    "businessPartner": 20002,
    "documentLinesFromDocument":
    [
        {
            "documentAmount": 0.0,
            "companyCurrencyAmount": 0.0,
            "sourceCurrencyAmount": 0.0,
            "sourceCurrency": "USD",
            "refDocument": "52011962",
            "documentLineText": "text here",
            "isAccountsPayable": "true",
            "businessPartner": "16959"
        }
    ]
}
```

## **Generic Dataloy API Fields**

The following fields exist for all Dataloy VMS API resources:

| Field Name       | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **key**          | <p>The ID of the entity. This can be used to:</p><ul><li>request that entity at a URL of the form <strong>/Entitytype/{key}</strong></li><li>or to represent the entity in a <strong>POST</strong> or <strong>PUT</strong> request</li></ul>                                                                                                                                                                                                                 |
|                  | The full URL of the entity.                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| **modifiedDate** | <ul><li>Last Modified Date</li><li>Object Changed by User or Recalculated by System</li></ul>                                                                                                                                                                                                                                                                                                                                                                |
| **createdDate**  | Date for Object Creation                                                                                                                                                                                                                                                                                                                                                                                                                                     |
|                  | <p>Defines the code property of a resource. The value is the name of another property which can be used to identify the resource and is, in many cases, functionally equivalent to the "key" propery.</p><p><em><strong>Note</strong>: Not all resources have a codeProperty.</em></p><p>Example:</p><p>When setting a currency either an invoice the key (ID) of that currency or the currencyCode (i.e. the codeProperty of Currency) can be used.<br></p> |
| **createdById**  | User key of the Dataloy VMS user that created the resource instnce initially.                                                                                                                                                                                                                                                                                                                                                                                |
| **changedById**  | User key of the Dataloy VMS user that updated the resource instance.                                                                                                                                                                                                                                                                                                                                                                                         |
| **remarks\[]**   | Array of remarks connected to the resouce instance                                                                                                                                                                                                                                                                                                                                                                                                           |

## **Date Format**

**From version 2.0.0 the date format has been changed to conform ISO 8601:**

yyyy-MM-ddThh:mm:ss\
\
Example: \
\
*2014-01-01T00:00:00*

**Versions prior to 2.0.0:**

Date format for JSON messages: yyyy-MM-dd hh:mm:ss\
\
Example:\
\
*2014-01-01 00:00:00*\
Date format for [filtering](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414908/Filtering): yyyy-MM-ddThh:mm:ss\
\
Example: \
\
*2014-01-01T00:00:00*

## **REST - Representational State Transfer**

A quick introduction to **REST** is available at <http://www.infoq.com/articles/rest-introduction>[.](http://www.infoq.com/articles/rest-introduction)

## **JSON - JavaScript Object Notation**

JSON is a text format that is natively supported by Javascript. It is less verbose than XML and is easier for users to read. JSON is not written in order, so fields might change position between calls. A quick introduction:  <http://www.json.org/>&#x20;

## **Tools for Simple Tests**

Several tools are available to aid the testing of the API. This enables a payload to be sent to a URL **with a specific type of request**, for example, GET, PUT, POST.

Examples of available tools (but NOT limited to):

*Chrome:*

* *Advanced REST client:* [*https://chrome.google.com/webstore/search/advanced%20rest%20client*](https://chrome.google.com/webstore/search/advanced%20rest%20client?utm_source=chrome-ntp-icon)
* *Postman:* [*https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en-US*](https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en-US)

*Firefox:*

* *Poster:* [*https://addons.mozilla.org/en-us/firefox/addon/poster/*](https://addons.mozilla.org/en-us/firefox/addon/poster/)&#x20;

***Note**: Dataloy recommends tools like JSONView to Chrome (to browse the API more conveniently when developing).*

Documentation of API resources is currently in progress. Presently the reference documentation is manually updated. (*More Information:* [*Accounting Integration API*](https://dataloy-cloud.atlassian.net/wiki/spaces/VMSINT/pages/923414837/Accounting+Integration+API)).\ <br>


# Data Model

{% embed url="<https://dataloy-systems.stoplight.io>" %}


# Filtering

**Dataloy REST API** uses a generic search/filtering functionality. In general, **all resources** supports filtering on **all properties** of that resource and linked resources (for exceptions, see [Limitations](#limitations)).

## **Syntax**

The filter query parameter has the following format:&#x20;

| `<Base URL>/<Resource>?filter=<json property>(OPERATOR)<value>` |
| --------------------------------------------------------------- |

Example that will return currency information for USD:

| `localhost/ws/rest/Currency?filter=currencyCode(EQ)USD` |
| ------------------------------------------------------- |

### Syntax Breakdown  **\<Base URL>**

For more information see [Getting Started with Dataloy REST API](/api-release-8.25/dataloy-rest-api/getting-started)\
&#x20;

**\<Resource>**&#x20;

Can be any of the [Resources](/api-release-8.25/dataloy-rest-api/data-model) available in the Dataloy API.

**\<json property>**&#x20;

Can be any json **property** of the [resource](/api-release-8.25/dataloy-rest-api/data-model) (for exceptions, see [Limitations](#limitations)).\ <br>

## **\<OPERATOR>**&#x20;

The operator is always:

* surrounded by parenthesis
* is always upper case

### **List of Operators**

<table data-full-width="true"><thead><tr><th>Operator</th><th>Description</th><th>API Version</th><th>Example</th></tr></thead><tbody><tr><td>(EQ)</td><td>Equals Exact Value, <em>case sensitive</em></td><td></td><td>Get a Document with document number 2707374: <strong>Document?filter=documentNo(EQ)2707374</strong></td></tr><tr><td>(NE)</td><td>Not Equal</td><td></td><td>Get all Documents not in company 1000: <strong>Document?filter=company.companyCode(NE)1000</strong></td></tr><tr><td>(GT)</td><td><p>Greater Than</p><p><em>ONLY numeric and date values</em></p></td><td></td><td>Get all Voyages modified since 2014-01-01 00:00:00, not including 2014-01-01 00:00:00: <strong>Voyage?filter=modifiedDate(GT)2014-01-01T00:00:00</strong></td></tr><tr><td>(GTE)</td><td><p>Greater Than or Equal</p><p><em>ONLY numeric and date values</em></p></td><td></td><td>Get all Voyages modified since 2014-01-01 00:00:00, including 2014-01-01 00:00:00: <strong>Voyage?filter=modifiedDate(GTE)2014-01-01T00:00:00</strong></td></tr><tr><td>(LT)</td><td><p>Lesser Than</p><p><em>ONLY numeric and date values</em></p></td><td></td><td>Get all Documents that has document amount less than 100000: <strong>Document?filter=documentAmount(LT)100000</strong></td></tr><tr><td>(LTE)</td><td><p>Lesser Than or Equal</p><p><em>ONLY numeric and date values</em></p></td><td></td><td>Get all Documents that has document amount less than 100000, including 100000: <strong>Document?filter=documentAmount(LT)100000</strong></td></tr><tr><td>(IN)</td><td>Equals One of the Elements in a Given List</td><td></td><td>Get all Documents that are ready for posting and has status type INI, INO, CRI or CRO: <strong>Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&#x26;filter=invoicingStatus.statusTypeCode(IN)(INI,INO,CRI,CRO)</strong></td></tr><tr><td>(NULL)</td><td>Filter for NULL values</td><td>2.10</td><td>Get all Documents without business partner: <strong>Document?filter=businessPartner(NULL)</strong></td></tr><tr><td>(NOTNULL)</td><td>Filter for NOT NULL values</td><td>2.10</td><td>Get all Voyages with vessel: <strong>Voyage?filter=vessel(NOTNULL)</strong></td></tr><tr><td>(LK)</td><td>Like operator</td><td>3.3</td><td>Get all BunkerOrder with externalReferenceNo containing the string "test" case sensitive: <strong>BunkerOrder?filter=externalReferenceNo(LK)test</strong></td></tr><tr><td>(LKIC)</td><td>Like ignore case operator</td><td>3.3</td><td>Get all BunkerOrder with externalReferenceNo containing the string "test" case insensitive<strong>:</strong> BunkerOrder?filter=externalReferenceNo(LKIC)test</td></tr><tr><td>(NLK)</td><td>Not like </td><td>8.5</td><td>Get all BunkerOrder with externalReferenceNo not containing the string "test" case sensitive: <strong>BunkerOrder?filter=externalReferenceNo(NLK)test</strong></td></tr><tr><td>(NLKIC)</td><td>Not like ignore case</td><td>8.5</td><td>Get all BunkerOrder with externalReferenceNo not containing the string "test" case insensitive: <strong>BunkerOrder?filter=externalReferenceNo(NLK)test</strong></td></tr><tr><td>(NOTIN)</td><td>Is not one of the elements in a given list</td><td>8.13</td><td>Get all Documents that are ready for posting and has status type other than CRI or CRO: Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&#x26;filter=invoicingStatus.statusTypeCode(NOTIN)(CRI,CRO)</td></tr></tbody></table>

### **\<value>**

* **Numeric Values** are straight forward. Can be integers or decimal numbers using a dot as decimal point. <br>
* **Dates** must be specified in the format: **yyyy-MM-ddTHH:mm:ss**
* **Strings** *can* be surrounded by double quotes, but it is generally not necessary. Even if the string has spaces.
* **Boolean** must be specified with 0 for false and 1 for tru&#x65;**.**

## **Combining Filters**

The filter URL parameter can be added multiple times to filter on multiple properties in one request. To do so, add a new filter parameter to the end of the URL

### **Syntax for Combining Filters**

| `<Base URL>/<Resource>?filter=<json property>(OPERATOR)<value>&filter=<json property 2>(OPERATOR)<value>` |
| --------------------------------------------------------------------------------------------------------- |

Example:

| `<Base URL>/Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&filter=invoicingStatus.statusTypeCode(IN)(INI,INO,CRI,CRO)` `Invoices ready to be transferred to accounting will be returned.` |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |

### **Properties for Sub Objects**

Filters can be used for sub objects by using a "dot path". Example of a sub object is commodity on Cargo:

```
Part of the Cargo resource as an example:
  
{
    "cargoReference": 12345,
    "freight": 20000,
    "cargoQuantity":100000,
    "commodity": {
            "commodityName": "Steel",
            "commodityCode": "10000",
            "key": 1069734,
            "self": "http://localhost:8080/ws/rest/Commodity/1069734"
    }
}
```

To search for cargoes with commodity steel:

| `<Base URL>/Cargo?filter=commodity.commodityCode(EQ)10000` |
| ---------------------------------------------------------- |

### **Limitations**

The following properties are currently not possible for filtering:

* self
* remarks

A few other properties are unsupported, these are documented for each resource.

## **Examples**

**Cargo**

Get Cargo with freight more than 1000000 and freightCurrency USD or EUR:

| `/Cargo?filter=freight(GT)1000000&filter=freightCurrency.currencyCode(IN)USD,EUR` |
| --------------------------------------------------------------------------------- |

**Document**

Get Documents with documentType "INV" and invoicingStatus "PEN"

| `/Document?filter=documentType.documentType(EQ)INV&filter=invoicingStatus.statusTypeCode(EQ)PEN` |
| ------------------------------------------------------------------------------------------------ |

**Voyage**&#x20;

Get Voyages for the vessel with vessel code ABRA

| `/Voyage?filter=voyageHeader.vesselCode.vesselCode(EQ)ABRA` |
| ----------------------------------------------------------- |

Get Voyage with reference number VES100

| `/Voyage?filter=voyageHeader.referenceNo(EQ)VES100` |
| --------------------------------------------------- |

Get Voyage with start date > 01.01.2016 and operator is user with userCode "BAK"

| `/Voyage?filter=voyageHeader.voyageStartDate(GT)2016-01-01T00:00:00&voyageHeader.operator.userCode(EQ)BAK` |
| ---------------------------------------------------------------------------------------------------------- |

Get Voyages that are operational for vessel ABRA

| `/Voyage?filter=voyageHeader.voyageStatus.statusTypeCode(EQ)OPR&filter=voyageHeader.vesselCode.vesselCode(EQ)ABRA` |
| ------------------------------------------------------------------------------------------------------------------ |

Get all Voyages that has Oslo as Load Port in 2015

| `/Voyage?filter=portCalls.reasonForCall.reasonForCall(EQ)L&filter=portCalls.port.portName(EQ)OSLO&filter=voyageHeader.voyageStartYear(EQ)2015` |
| ---------------------------------------------------------------------------------------------------------------------------------------------- |


# Sorting

It is possible sort the result of any search. The following type of sorting are supported:

* ASCENDING (ascending order,  case - or database sensitive)
* ASCENDING INSENSITIVE (ascending order, case-insensitive)
* DESCENDING (descending order, case - or database - sensitive)
* DESCENDING INSENSITIVE (descending order, case-insensitive)

ASCENDING

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(AS)>

ASCENDING INSENSITIVE

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(ASI)>

DESCENDING&#x20;

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(DS)>

DESCENDING INSENSITIVE

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(DSI>)

&#x20;

It is possible use sorting in combination with any filter and pagination:

<http://localhost:8080/ws/rest/Vessel?sort=vesselName(DSI)&filter=flag.countryCode(EQ)HK&pageNumber=4&limit=10>\
\
Calculated fields are sorted after data retrieval and only consider records in the response. See the data model documentation for field specifications: <https://dataloy-systems.stoplight.io/>


# Pagination

To return a defined number of objects for any Dataloy resource it has to be specified in the URL the page number, **pageNumber** parameter, and the number of objects that the page has to contain, **limit** parameter. For example:

[\
/ws/rest/Document?pageNumber=1\&limit=10\&filter=documentAmount(GT)100000](http://localhost:8080/ws/rest/Document?\&pageNumber=1\&limit=10\&filter=documentAmount\(GT\)100000)

it will return the first page containing at max 10 Document objects having the property documentAmount greater than 100000. In the response will be added an header parameter called **totalObjectsNumber** that indicates the total number of objects of the endpoint.

From **API 5.18** is possible to avoid to get **totalObjectsNumber**  sending the HTTP header parameter **noCount = YES,** this will allow a bit better performance.

Another example:

[/ws/rest/Vessel?filter=flag.countryCode(EQ)HK\&pageNumber=4\&limit=10](http://localhost:8080/ws/rest/Vessel?filter=flag.countryCode\(EQ\)HK\&pageNumber=4\&limit=10)

<br>

it will return the fourth page containing at max 10 Vessels objects having the countryCode property equals to EQ.


# Adjust Number of Fields to be Returned from a Request

**I**t is possible to adjust the number of fields that have to be returned from a resource. It's possible to both increase and decreases the number of fields from the default view. So if only field A and B from a resource is needed and the other X number of fields can be ignored, it can be specified in the header of the request. This will reduce the overhead of data transferred and improve performance. If more fields are needed in one request, to avoid making a second request to get all the data that is needed, this can also be done. So if fields A, B and C are returned in the default view, but also field D is needed, this can be specified in the header.

## **Customize the Number of Fields returned**

Retrieving data from a resource may provide more information than needed. Fields with data to be returned can be specified by first adding a header field and then specifying the fields to be returned in the header field value. The header field value is specified as a **JSON message** following the same structure as the resource structure that is used when making the request. This enables fields to be specified in main- and sub-objects. &#x20;

The examples listed illustrate how it is used for a business partner. The procedure is, however, the same for all resources. The key and self attribute will always be returned, but the number of displayed/hidden fields can be customized.

Business Partner without any field restriction will result in ( *view example*):

```
{
    "businessPartnerName": "Big Customer",
    "businessPartnerSort": "BIG.",
    "businessPartnerCode": "45999",
    "codeProperty": "businessPartnerCode",
    "bankAccounts": [],
    "individuals": [],
    "user": null,
    "createdDate": "2014-01-27T18:38:52",
    "changedById": 3689599,
    "createdById": 1045293,
    "externalObjectKey": null,
    "modifiedDate": "2024-09-29T10:59:34",
    "portAgentType": null,
    "bankAccount": null,
    "paymentTerms": {
        "key": 1004281,
        "self": "https://dev.dataloy.com/ws/rest/PaymentTerms/1004281"
    },
    "businessUnit": {
        "key": 1000576,
        "self": "https://dev.dataloy.com/ws/rest/BusinessUnit/1000576"
    },
    "baselineTerm": {
        "key": 1004265,
        "self": "https://dev.dataloy.com/ws/rest/BaselineTerm/1004265"
    },
    "contactInfo": [
        {
            "key": 5987711,
            "self": "https://dev.dataloy.com/ws/rest/ContactInfo/5987711"
        }
    ],
    "businessPartnerName2": null,
    "companyRegistrationNo": "987987987",
    "isInterCompany": false,
    "isTotalCommissionPayable": false,
    "maxAdvancePaymentPercent": 100,
    "rating": null,
    "ratingExpiryDate": null,
    "vatNumber": null,
    "addresses": [
        {
            "key": 5993125,
            "self": "https://dev.dataloy.com/ws/rest/Address/5993125"
        }
    ],
    "businessPartnerLink": {
        "key": 1004433,
        "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1004433"
    },
    "businessPartnerType": {
        "key": 1000032,
        "self": "https://dev.dataloy.com/ws/rest/BusinessPartnerType/1000032"
    },
    "companyBankAccount": null,
    "www": [
        {
            "key": 5987713,
            "self": "https://dev.dataloy.com/ws/rest/Www/5987713"
        }
    ],
    "payee": {
        "key": 1004433,
        "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1004433"
    },
    "remarks": [],
    "isObjectActive": true,
    "key": 1045574,
    "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1045574"
}

```

**Examples**

1\. Return Business Partner name only:

**fields: {"businessPartnerName":"\*"}**

```
{
  "businessPartnerName": "Big Customer",
  "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1045574",
  "key": 1045574
}
```

2\. Return address1 only:

**fields: {"addresses": {"address1":"\*"}}**

{% hint style="danger" %}
Note that addresses is an array, but for the fields value it should be treated as a field, so do not include \[ ]
{% endhint %}

```
{
  "addresses": [
    {
      "address1": "Halfdan Kjerulfs gate 4",
      "key": 5993125,
      "self": "https://dev.dataloy.com/ws/rest/Address/5993125"
    }
  ],
  "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1045574",
  "key": 1045574
}
```

3\. Return Business Partner name and address1:

**fields: {"businessPartnerName":"\*", "addresses":{"address1":"\*"}}**

```
{
  "businessPartnerName": "Big Customer",
  "addresses": [
    {
      "address1": "Halfdan Kjerulfs gate 4",
      "key": 5993125,
      "self": "https://dev.dataloy.com/ws/rest/Address/5993125"
    }
  ],
 "self": "https://dev.dataloy.com/ws/rest/BusinessPartner/1045574",
 "key": 1045574
}
```


# Webhooks

#### Webhooks <a href="#webhooks-webhooks" id="webhooks-webhooks"></a>

Webhooks are user-defined HTTP callbacks that receive events for the subscribed event types. Webhook notifications are asynchronous, the order is not guaranteed.

Events are categorised into event types. Events occur due to changes in the state of a resource, such as when a voyage is updated. When an event occurs, the registered applications are notified via HTTP POST. The POST contains the event details, including the event type that caused the event.&#x20;

When an application receives the event, it must respond with a 200-level HTTP status code.

#### **Subscription** <a href="#webhooks-subscription" id="webhooks-subscription"></a>

When a webhook subscription is made, through the resource WebhookSubscription, for a Dataloy object, BunkerOrder for instance, the subscribed webhook will be pushed with all the changes that occurred to the subscribed object and its object hierarchy. So if a PortCall of the subscribed BunkerOrder is updated the webhook will be notified.

{% hint style="danger" %}
The Remarks are not part of the webhook process. It is not possible to get notifications of changes in Remarks.
{% endhint %}

The Dataloy webhook event type is a concatenation of the following attributes:

* Resource name (Document, Voyage, ..)
* Operation type (C,U, D create, update, delete)
* Object key

\
The user can subscribe to a webhook for a given event, for example:

| Cargo.C         | Notifies when a Cargo is created                                 |
| --------------- | ---------------------------------------------------------------- |
| Document.D      | Notifies when a Document is deleted.                             |
| Voyage.U        | Notifies when a Voyage is updated.                               |
| Voyage.U.793628 | Will notify when voyage, having voyage.key = 793628, is updated. |

{% hint style="danger" %}
**Automatic Deactivation of subscription**

If the subscribing system is unavailable or takes too long to respond, the server will deactivate the subscription after attempting 5 times (once a minute). The number of attempts and the interval between each attempt can be configured.

Deactivated subscriptions cannot be reactivated, a new subscription must be created if needed.&#x20;

***Email alert when a subscription is de-activated:** Add the desired email address (e.g. to the IT ops team) to the API user (in User Administration) to receive an email notification if a subscription is de-activated.*
{% endhint %}

The message sent to the subscribed endpoint is set in the body of the POST method. The message is a JSON object and has the following structure:

```
{
 "id": "1573335-244070007",
 "eventTime": "2016-09-14T13:37:26",
 "objectType": "PortCall",
 "eventType": "U",
 "dataloyObject":189126972,
 "dataloyObjectSelf":"http://localhost:8080/ws/rest/PortCall/7823672"
 "subscription":{
            "key":243885046,
            "self":"http://localhost:8080/ws/rest/WebhookSubscription/243885046"
            "objectType":"BunkerOrder",
            "dataloyObject":244070007,
            "eventType": "U",
             "url":"http://test1.dataloy.com:8080/webhook/"
   }
"resource":{ 
      "key":244070007,
      "self":"http://localhost:8080/ws/rest/BunkerOrder/244070007",
      "vessel":{ 
         "vesselName":"VESSEL1",
         "key":188616815,
         "self":"http://localhost:8080/ws/rest/Vessel/188616815"
      },
      "currency":{ 
         "currencyCode":"USD",
         "currencyName":"U.S. DOLLAR",
         "key":400132,
         "self":"http://localhost:8080/ws/rest/Currency/400132"
      },
      "exchangeRate":3.0,
      "modifiedDate":"2016-09-21T06:38:29",
      "portCall":{ 
         "key":189126972,
         "self":"http://localhost:8080/ws/rest/PortCall/189126972",
         "eventLogs":[ 
            { 
               "key":189126978,
               "self":"http://localhost:8080/ws/rest/EventLog/189126978",
               "event":{ 
                  "key":1000052,
                  "self":"http://localhost:8080/ws/rest/Event/1000052",
                  "eventCode":"DEP",
                  "eventDesc":"Departed"
               },
               "eventLogDate":"2015-02-13T17:18:00"
            },
            { 
               "key":189126974,
               "self":"http://localhost:8080/ws/rest/EventLog/189126974",
               "event":{ 
                  "key":1000050,
                  "self":"http://localhost:8080/ws/rest/Event/1000050",
                  "eventCode":"ARR",
                  "eventDesc":"Arrived"
               },
               "eventLogDate":"2015-02-06T20:18:00"
            },
            { 
               "key":189126976,
               "self":"http://localhost:8080/ws/rest/EventLog/189126976",
               "event":{ 
                  "key":1000051,
                  "self":"http://localhost:8080/ws/rest/Event/1000051",
                  "eventCode":"BRT",
                  "eventDesc":"Berthed"
               },
               "eventLogDate":"2015-02-07T10:06:00"
            }
         ]
      },
      "extraCost":0.0,
      "bunkeredDate":"2016-01-01T00:00:00",
      "orderDate":"2016-09-06T10:16:36",
      "bunkerPaidBy":null,
      "createdDate":"2016-09-21T06:12:42",
      "createdById":999999,
      "bunkerOrderStatus":{ 
         "key":243093653,
         "self":"http://localhost:8080/ws/rest/StatusType/243093653",
         "statusTypeDesc":"Requirement",
         "statusTypeCode":"REQBO"
      },
      "externalReferenceNo":null,
      "bunkerOrderLines":[ 
         { 
            "key":244070009,
            "self":"http://localhost:8080/ws/rest/BunkerOrderLine/244070009",
            "minQuantity":50.0,
            "maxQuantity":100.0,
            "extraCost":0.0,
            "bunkeredQuantity":111.0,
            "unitPrice":100.0,
            "bunkerType":{ 
               "key":73564540,
               "self":"http://localhost:8080/ws/rest/BunkerType/73564540",
               "isoCode":null,
               "isoYear":null,
               "bunkerTypeCode":"FO",
               "bunkerTypeDesc":"FO",
               "sulphurPercent":null
            }
         }
      ],
      "company":null,
      "bunkerBroker":{ 
         "businessPartnerName":"BUSINESS PARTNER 1",
         "businessPartnerSort":"BUSINESS PARTNER 1",
         "businessPartnerCode":"1111",
         "businessPartnerType":{ 
            "businessPartnerType":"BS",
            "businessPartnerTypeDesc":"Bunker Supplier",
            "key":1000034,
            "self":"http://localhost:8080/ws/rest/BusinessPartnerType/1000034"
         },
         "key":39697371,
         "self":"http://localhost:8080/ws/rest/BusinessPartner/39697371"
      },
      "bunkerAccountOf":null,
      "bunkerSupplier":{ 
         "businessPartnerName":"BUSINESS PARTNER 2",
         "businessPartnerSort":"BUSINESS PARTNER 2",
         "businessPartnerCode":"22222",
         "businessPartnerType":{ 
            "businessPartnerType":"BS",
            "businessPartnerTypeDesc":"Bunker Supplier",
            "key":1000034,
            "self":"http://localhost:8080/ws/rest/BusinessPartnerType/1000034"
         },
         "key":39697206,
         "self":"http://localhost:8080/ws/rest/BusinessPartner/39697206"
      },
      "remarks":[ 
 
      ]
   }
}
```

The attributes have the following meaning:

| id                | Unique identifier of the notification                                                                                                                          |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| eventTime         | The time when the event occurred                                                                                                                               |
| objectType        | Name of the changed Dataloy object                                                                                                                             |
| dataloyObject     | The primary key of the changed Dataloy object (it can be different from the subscribed object, it can be an object in the hierarchy of the subscribed object ) |
| eventType         | C for creation, U for update, D for deletion                                                                                                                   |
| dataloyObjectSelf | the Dataloy URL of the changed object                                                                                                                          |
| subscription      | Subscription data:                                                                                                                                             |
| resource          | The JSON of the DataloyObject that the subscription refers to                                                                                                  |

### New functionalities since [version 3.9](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404308/Dataloy+API+3.9.0+Release+Notes) <a href="#webhooks-newfunctionalitiessinceversion3.9" id="webhooks-newfunctionalitiessinceversion3.9"></a>

With API 3.9 the following new functionalities have been introduced:

* Possibility to be notified  of changes via email
* Possibility to customize the JSON pushed as [Adjust Number of Fields to be Returned from a Request](/api-release-8.25/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request)
* Possibility to filter  changes that have to be pushed via expressions
* Possibility to filter  changes that have to be pushed via scripts

#### Notifications via email <a href="#webhooks-notificationsviaemail" id="webhooks-notificationsviaemail"></a>

To be notified via email in the WebhookSubscription must be specified the **channelInfo** property with **channelType** **EMAIL** and the **URL** with the email address:

```
{
       "channelInfo": {
           "url": "info@dataloy.com",
           "channelType": "EMAIL"
       }
   }
```

channelType can be EMAIL or HTTP if HTTP is set the URL attribute must contain the endpoint where to push notifications.

#### Possibility to customize the JSON pushed <a href="#webhooks-possibilitytocustomizethejsonpushed" id="webhooks-possibilitytocustomizethejsonpushed"></a>

Through the attribute **JSON** of WebhookSubscription is possible to specify which attributes of the object must be pushed (see [Adjust Number of Fields to be Returned from a Request](/api-release-8.25/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request)). The value of JSON must be encoded with Base64.

For instance, if the subscription is for the object BunkerOrderLine a possible value for the JSON attribute could be:

```
{"extraCost":"*"}
```

that encoded will be&#x20;

```
"json": "ew0KCSJleHRyYUNvc3QiOiIqIg0KfQ=="
```

In this way the sub-object in the attribute **resource**  will be smaller:

```
{ 
   "id":"245-320996749",
   "eventTime":"2018-01-30T10:42:11",
   "eventType":"U",
   "objectType":"BunkerOrderLine",
   "dataloyObject":320996749,
   "dataloyObjectSelf":"http://platform-dev.dataloy.com:80/ws/rest/BunkerOrderLine/320996749",
   "subscription":{ 
      "key":332501529,
      "self":"http://platform-dev.dataloy.com:80/ws/rest/WebhookSubscription/332501529",
      "isSubscriptionActive":true,
      "user":{ 
         "key":999999,
         "self":"http://platform-dev.dataloy.com:80/ws/rest/User/999999",
         "userCode":"DATALOY",
         "userName":"dataloy"
      },
      "objectType":null,
      "dataloyObject":null,
      "url":null,
      "dlpAlertScript":{ 
         "key":318269643,
         "self":"http://platform-dev.dataloy.com:80/ws/rest/DlpAlertScript/318269643",
         "scriptCode":"BUP",
         "scriptName":"Bunkered Unit Price updated"
      },
      "eventType":null,
      "unsubscriptionDate":null,
      "channelInfo":{ 
         "key":332501528,
         "self":"http://platform-dev.dataloy.com:80/ws/rest/ChannelInfo/332501528",
         "channelType":{ 
            "key":311504704,
            "self":"http://platform-dev.dataloy.com:80/ws/rest/ChannelType/311504704",
            "channelTypeCode":"EMAIL"
         },
         "url":"ab@dataloy.com"
      }
   },
   "resource":{ 
      "key":320996749,
      "self":"http://platform-dev.dataloy.com:80/ws/rest/BunkerOrderLine/320996749",
      "extraCost":0.0
   }
}
```

#### Possibility to filter  changes that have to be pushed via expressions <a href="#webhooks-possibilitytofilterchangesthathavetobepushedviaexpressions" id="webhooks-possibilitytofilterchangesthathavetobepushedviaexpressions"></a>

Through the attribute **expression** of WebhookSubscription is possible to write a **Java expression** against the object changed. At runtime If the expression return true the notification will be sent,  otherwise no.

For instance, if the subscription is done for the object BunkerOrderLine a possible expression could be:

| `dlpObject.getUnitPrice()!=null` `&& ( dlpObject.getUnitPrice()>10` `\|\|  dlpObject.getUnitPrice()<100)` |
| --------------------------------------------------------------------------------------------------------- |

that for any changes at any BunkerOrderLine object will check if the unit price is not null and its value is between 10 and 100, if yes the notification will be sent.&#x20;

In the expression must be used the variable **dlpObject** to refer to the changed object, the object will contain the new values. If the expression needs to check also the previous values of the object, the variable **oldDlpObject** can be used.

For instance:

| `oldDlpObject.getExtraCost()!=null` `&& dlpObject.getExtraCost()!=null` `&& dlpObject.getExtraCost()> oldDlpObject.getExtraCost()` |
| ---------------------------------------------------------------------------------------------------------------------------------- |

that will check if the new extra cost of a BunkerOrder is greater than the previous one.

If you want to be notified when an attribute change value from null to not null:

| `oldDlpObject.getReferenceNo() == null` `&& dlpObject.getReferenceNo() != null` |
| ------------------------------------------------------------------------------- |

**The old values will be accessible only for those Dataloy object changed via Dataloy API.**

#### Possibility to filter  changes that have to be pushed via scripts <a href="#webhooks-possibilitytofilterchangesthathavetobepushedviascripts" id="webhooks-possibilitytofilterchangesthathavetobepushedviascripts"></a>

Contact Dataloy to have info regarding scripts.

### New functionalities since [version 3.16](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404337/Dataloy+API+3.16.0+Release+Notes) <a href="#webhooks-newfunctionalitiessinceversion3.16" id="webhooks-newfunctionalitiessinceversion3.16"></a>

In version 3.16 (and later) it is possible to decide if a webhook subscription should only be  notified on changes to the object subscribed. So for instance making a subscription for the Voyage object, the changes that will occur to linked objects, like PortCall, Cargo, etc, will be not notified. To achieve this behaviour a new boolean attribute called **onlyMainObject** in WebhookSubscription has been added, setting it to true only the changes for the subscribed will be sent.

A new endpoint in WebhookSubscription **POST:sendFailedNotifications** has been added to resend manually the failed webhook notification.

### New functionalities since version 5.23 <a href="#webhooks-newfunctionalitiessinceversion5.23" id="webhooks-newfunctionalitiessinceversion5.23"></a>

In version 5.23 (and later) it is possible to decide if a webhook subscription should only be notified with the raw object, without the envelope payload.  To achieve this behavior a new boolean attribute called **rawObject** in WebhookSubscription has been added, setting it to true the raw object will be sent.

### New functionalities since version 5.24 <a href="#webhooks-newfunctionalitiessinceversion5.24" id="webhooks-newfunctionalitiessinceversion5.24"></a>

A new attribute **xsl** has been added which allows you to store an XSL stylesheet to transform the subscribed object to XML. The value of the field must be encoded with Base64. This is part only of Enterprise API.

### New functionalities since version[ ](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404337/Dataloy+API+3.16.0+Release+Notes)6.44 <a href="#webhooks-newfunctionalitiessinceversion3.16" id="webhooks-newfunctionalitiessinceversion3.16"></a>

In order to not get notified by the changes done by the user of the subscription the attribute **notSendMyChanges** can be set to true.

### Supported Methods <a href="#webhooks-supportedmethods" id="webhooks-supportedmethods"></a>

**GET /WebhookSubscription**

Get a list of WebhookSubscription objects. Filter to avoid huge amounts of data (*see* [*Filtering* ](/api-release-8.25/dataloy-rest-api/filtering)*documentation for examples*). &#x20;

**GET /WebhookSubscription/{key}**

Get a single WebhookSubscription object.

**Example GET Return Body**&#x20;

```
{
  "key": 243907762,
  "self": "http://localhost:8080/ws/rest/WebhookSubscription/243907762",
  "isSubscriptionActive": true,
  "unsubscribed": false,
  "eventType": "U",
  "dataloyObject": 243896793,
  "createdDate": "2016-09-16T08:35:46",
  "modifiedDate": "2016-09-16T08:35:46",
  "createdById": 999999,
  "objectType": "BunkerOrder",
  "user": {
    "key": 999999,
    "self": "http://localhost:8080/ws/rest/User/999999",
    "userName": "dataloy",
    "userCode": "DATALOY"
  },
  "url": "http://test1.dataloy.com:8080/webhook/",
  "unsubscriptionDate": null,
  "webhookUsername": null,
  "webhookPassword": null,
  "remarks": []
}
```

since API 3.9:

```
{
    "key": 320298564,
    "self": "http://platform-dev.dataloy.com:80/ws/rest/WebhookSubscription/320298564",
    "isSubscriptionActive": true,
    "unsubscribed": false,
    "user": {
        "key": 999999,
        "self": "http://platform-dev.dataloy.com:80/ws/rest/User/999999",
        "userCode": "DATALOY",
        "userName": "dataloy"
    },
    "objectType": "BunkerOrder",
    "createdDate": "2018-01-11T10:53:14",
    "url": "http://platform-dev.dataloy.com/ws/rest/dataloy/sendJson",
    "modifiedDate": "2018-01-11T10:53:14",
    "createdById": 999999,
    "dataloyObject": null,
    "expression": null,
    "dlpAlertScript": null,
    "eventType": "U",
    "unsubscriptionDate": null,
    "scriptParameterValues": [],
    "useMsg": false,
    "json": "{}",
    "webhookPassword": "XXX",
    "webhookUsername": "dataloy",
    "channelInfo": null,
    "remarks": []
}
```

**POST /WebhookSubscription**

Create a new WebhookSubscription.

**Examples**

Create a subscription to get notifications when the BunkerOrder with primary key 243896793 is updated:

```
{
    "eventType":"U",
    "user":999999,
    "objectType":"BunkerOrder",
    "dataloyObject":243896793,
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when any BunkerOrder is updated:

```
{
    "eventType":"U",
    "user":999999,
    "objectType":"BunkerOrder",
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when a BunkerOrder is created:&#x20;

```
{
    "eventType":"C",
    "user":999999,
    "objectType":"BunkerOrder",
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when the BunkerOrder with primary key 243896793 is deleted:&#x20;

```
{
    "eventType":"D",
    "user":999999,
    "objectType":"BunkerOrder",
    "dataloyObject":243896793,
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when any BunkerOrder is deleted:&#x20;

```

{
    "eventType":"D",
    "user":999999,
    "objectType":"BunkerOrder",
    "url":"http://test1.dataloy.com:8080/webhook/"
     
}
```

Create a subscription to get notifications when any BunkerOrder is updated  via email, since API 3.9:

```
{
    "eventType":"U",
    "user":999999,
    "objectType":"BunkerOrder",
    "channelInfo":{ 
         "url": "info@dataloy.com",
         "channelType": "EMAIL"
    }
}
```

Create a subscription to get notifications only when a Voyage object is changed, since API 3.16:

```
{
    "eventType":"U",
    "user":999999,
    "objectType":"Voyage",
    "channelInfo":{ 
         "url": "info@dataloy.com",
         "channelType": "EMAIL"
    },
    "onlyMainObject": true
}
```

**PUT /WebhookSubscription/{key}**

Only the following attributes can be updated:

* unsubscribed
* url
* webhookUsername
* webhookPassword

Since API 3.9 is possible to change also these other attributes:

* channelInfo
* json
* expression
* dlpAlertScript
* scriptParameterValues
* useMsg

To unsubscribe a subscription the following JSON must be sent. It is not possible to update the subscription if it has been unsubscribed:

```
{
    "unsubscribed": true   
}
```

**DELETE /WebhookSubscription/{key}**

To delete a WebhookSubscription first it has to be unsubscribed. **It is not possible to delete** **WebhookSubscription that got Webhook notifications, regardless that it has been unsubscribed or not**.


# Expression Builder

## Overview

The Expression Builder is a visual tool for creating webhook filters without writing code. Filter your webhook notifications to only receive updates that match specific criteria.

**Available when creating and maintaining:**

* Webhook subscriptions [(API documentation)](/api-release-8.25/dataloy-rest-api/webhooks)
* Subscription templates

**Example**: Instead of getting notified about all voyage updates, only get notified for voyages with status "Nominated" or voyages longer than 30 days.

## Add Your First Condition

1. Click **+ Add Condition**
2. Click field to open the field selector and select a "Field" (e.g., `voyageHeader.voyageStatus.statusTypeDesc`).&#x20;
3. Choose an "Operator" (=, >, <, etc.)
4. Enter the "Value" (e.g., "Nominated")

<figure><img src="/files/rS0ceqC1ajLB1Sg0o58A" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Notice the expression preview: `voyageHeader.voyageStatus.statusTypeDesc = "Nominated"`
{% endhint %}

## Add Multiple Conditions

Click **+ Add Condition** again to add more filters:

* By default, conditions use **"Match all"** (AND logic) – both must be true
* Switch to **"Match any"** (OR logic) – either condition can be true

<figure><img src="/files/U0M2VHyyi0xNq38bllFB" alt=""><figcaption></figcaption></figure>

**Match all example**: `statusTypeDesc = "Nominated" AND daysCanal > 1`\
**Match any example**: `statusTypeDesc = "Nominated" OR daysCanal > 1`

## Create Groups for Complex Logic

Click **+ Add Group** to create parentheses around conditions:

<figure><img src="/files/mJ5YraRu9EVSxWQZJu0e" alt=""><figcaption></figcaption></figure>

**Result**: `daysCanal > 1 AND (daysTotal < 10 OR daysTotalAtSea < 5)`

## Compare to Field

Instead of comparing to a static value, you can compare one field to another field by toggling **Compare to Field**.

<figure><img src="/files/tRgpRao26egQi0dUvKb5" alt=""><figcaption></figcaption></figure>

**Use case**: Get notified when loading takes longer than discharging:

```
daysLoading > daysDischarging
```

## Previous vs Current Values

When subscribing to updates, you can compare current and previous field values:

* **Previous**: The field value before the update
* **Current**: The field value after the update

**Example**: If voyage daysLoading change from 2.3 to 2.5:

* Previous value = 2.3
* Current value = 2.5

<figure><img src="/files/5pMZRVmqrGlRBWYXYAbZ" alt=""><figcaption></figcaption></figure>

Get notified when loading days increases:

```
prev.daysLoading < daysLoading
```


# Webhooks - New functionalities

### Alerts Menu Item

Webhooks is moved out from Setup to Alerts Menu Item on VMS web. The Alerts menu group has several menu items

* Webhooks - shows the list of subscriptions made by the user if the user is a non-administrative role and shows all the subscriptions in the system for an administrator user
* Notifications - shows the list of Notifications for all the subscriptions visible for the user.

#### Webhooks&#x20;

Clicking one of the rows in webhooks, opens the webhook subscription drawer with the tabs; Overview, Notifications, Comments and attachments.  While Overview has some new additions to it, Comments remain the same from before.

<figure><img src="/files/2Zk3Cr6hVjZnwh4TLa8p" alt=""><figcaption></figcaption></figure>

* Notifications tab in the subscription drawer includes the list of notifications filtered for the selected subscription. From 6.10.0, this list is updated to be similar to the other lists on VMS web with enabled filters and sorting.

<figure><img src="/files/4H5Q6ipCtxC6m0BoMdM7" alt=""><figcaption></figcaption></figure>

* Further clicking on one of the rows in the notifications list on subscription drawer, we can see the details of the Notification Msg sent for the subscription along with the error msg if the msg sending failed.

<figure><img src="/files/UPtSiXvH4mSlhrJNfEWD" alt=""><figcaption></figcaption></figure>

## New functionality

{% tabs %}
{% tab title="Prevent Unsubscription" %}
A new attribute, called **doNotUnsubscribe** (**Prevent Unsubscription**)**,** has been added to prevent that the subscription will get unsubscribed by the system. Also if the endpoint is not reachable for more times than the max number of attempts set for the given server.&#x20;

<figure><img src="/files/sP336o2VcGoPYnZLoYYy" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Template Message" %}
Introduced the possibility for users to define a message template that should be used when sending notifications for a webhook subscription.

When creating a Webhook Subscription, provide a text string for the attribute **templateMsg**. Attributes from the updated object can be included in the notification text through the format `{{attributeName}}.`

For example, when creating a subscription on Bank object , the user can use a templateMsg like *‘Bank with Name {{bankName}} is changed by {{changedById}} .*

<figure><img src="/files/POTZCkVTHxYmnf3Hmk7F" alt=""><figcaption></figcaption></figure>

This would result in the below notification for the user (example data, for reference only)

<figure><img src="/files/Tx0fXA71e4f5Mb6Gr53o" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Custom Schedule" %}
Webhooks can be set to trigger automatically on a set schedule with the **webhookSchedule** attribute (only possible on Webhooks with Alert Scripts).

<figure><img src="/files/niPWzRZwfyepw0iw4nkI" alt=""><figcaption></figcaption></figure>

Preview of example above as part of an api request for creating a Webhook Subscription.

```
"webhookSchedule": {
    "intervalHours": 24,
    "intervalMinute": 0,
    "startupTimeHours": 12,
    "startupTimeMinutes": 0
}
```

{% endtab %}
{% endtabs %}

#### &#x20; Notifications

* Holds the list of notifications for those subscriptions which the user has access to.
  * Administrator can access all the notifications for all the subscriptions available in the system, while non admin users can access only the subscriptions for the given logged in user. For example,

<figure><img src="/files/A094xNI0PAyuki6foweA" alt=""><figcaption></figcaption></figure>


# Master data Objects

It is possible to activate and deactivate any Master Data object. A new property has been added for this purpose, **isObjectActive.**

To deactivate an object the following JSON has to be used in the PUT method:

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
	"isObjectActive": false
}
</code></pre></td></tr></tbody></table>

\
To activate an object the following JSON has to be used in the PUT method:

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>{
	"isObjectActive": true
}
</code></pre></td></tr></tbody></table>

Master Data objects has to be deactivated before they can be deleted.

{% hint style="info" %}
Deactivated objects are not included in standard Master Data list query results. To work with these objects:

#### Retrieving Deactivated Objects

* **Via List Query**: To retrieve deactivated objects in a list query, add the filter parameter `isObjectActive(EQ)false` to your request.
* **Via Direct Access**: Individual deactivated objects remain accessible by their unique key, regardless of activation status.

#### Example using BusinessPartner master data object

```
// Standard query - returns only active business partners
GET /BusinessPartner

// Query deactivated business partners
GET /BusinessPartner?filter=isObjectActive(EQ)false

// Retrieving specific deactivated business partner by key
GET /BusinessPartner/{objectKey}
```

{% endhint %}


# Attachments

Since API 3.3 Remark has a new attribute **attachments** that contains a list of Attachment objects. The Attachment resource has an attribute called **file** where can be stored the content of the file encoded in Base64.

The attribute **fileName** is mandatory, the attribute "filesize" is not mandatory but the client should pass it.

The two resources can be manipulated exactly as all other resources.

**When a new Remark is posted with attachments in the JSON the source field must be before the attachments field.**

When getting an attachment, data can be encoded in base64, but also unencoded. Attachments added from the API will be encoded and attachment added from the Java VMS client may be unencoded.

**Some examples**

Create a new remark with a file attached:

POST: [http://{URL}/ws/rest/Remark](http://localhost:8080/ws/rest/Remark)\
BODY:

```
{
  "remarkTitle": "test 1",
  "source": 19637583,
  "attachments": [
    {
      
      "file":"small file 1",
      "fileName":"test1.txt"
    }
  ]
}
```

Attach an Attachment to an existing Remark

PUT: [http://{URL}/ws/rest/Remark/244324058](http://localhost:8080/ws/rest/Remark/244324058)\
BODY:

```
{
  "attachments": [
    {
      "file":"small file 2",
      "fileName":"test2.txt"
    }
  ]
}
```


# Audit Log

The endpoint AuditLog (<https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/audit-log>) can be used to get all changes of any object in the data model.

To get the changes of a given object with key KEY\_X:

* {BASE\_URL}/ws/rest/AuditLog?filter=source(EQ)KEY\_X

In the same request send the HTTP Header parameter **fields** with this JSON

```json
{"objectName":"*","attributeName":"*","actionTime":"*","entryText":"*","source":"*","newValue":"*","oldValue":"*","isChangedByUser":"*","action":{"actionName":"*"},"user":{"userName":"*"}}
```

The response will be an array of AuditLog objects:

```json
[
    {
        "key": 8345668,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/8345668",
        "objectName": "Voyage",
        "attributeName": "ladenConsumption",
        "source": 8336217,
        "user": {
            "key": 3689599,
            "self": "https://dev.dataloy.com/ws/rest/User/3689599",
            "userName": "Andrea Biasillo"
        },
        "actionTime": "2023-03-03T19:23:00",
        "entryText": "Field update: ladenConsumption",
        "isChangedByUser": true,
        "newValue": "83.29555785678073",
        "oldValue": "67.03034584820784",
        "action": {
            "key": 1000009,
            "self": "https://dev.dataloy.com/ws/rest/Action/1000009",
            "actionName": "EDIT"
        }
    },
    {
        "key": 8345669,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/8345669",
        "objectName": "Voyage",
        "attributeName": "co2Laden",
        "source": 8336217,
        "user": {
            "key": 3689599,
            "self": "https://dev.dataloy.com/ws/rest/User/3689599",
            "userName": "Andrea Biasillo"
        },
        "actionTime": "2023-03-03T19:23:00",
        "entryText": "Field update: co2Laden",
        "isChangedByUser": true,
        "newValue": "267.045558488839",
        "oldValue": "214.89928878935433",
        "action": {
            "key": 1000009,
            "self": "https://dev.dataloy.com/ws/rest/Action/1000009",
            "actionName": "EDIT"
        }
    },
    {
        "key": 8345670,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/8345670",
        "objectName": "Voyage",
        "attributeName": "tcResultDay",
        "source": 8336217,
        "user": {
            "key": 3689599,
            "self": "https://dev.dataloy.com/ws/rest/User/3689599",
            "userName": "Andrea Biasillo"
        },
        "actionTime": "2023-03-03T19:23:00",
        "entryText": "Field update: tcResultDay",
        "isChangedByUser": true,
        "newValue": "4877.341669917246",
        "oldValue": "6227.220974136807",
        "action": {
            "key": 1000009,
            "self": "https://dev.dataloy.com/ws/rest/Action/1000009",
            "actionName": "EDIT"
        }
    },
    {
        "key": 8345671,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/8345671",
        "objectName": "Voyage",
        "attributeName": "ballastConsumption",
        "source": 8336217,
        "user": {
            "key": 3689599,
            "self": "https://dev.dataloy.com/ws/rest/User/3689599",
            "userName": "Andrea Biasillo"
        },
        "actionTime": "2023-03-03T19:23:00",
        "entryText": "Field update: ballastConsumption",
        "isChangedByUser": true,
        "newValue": "42.7633723560667",
        "oldValue": "42.90031887514484",
        "action": {
            "key": 1000009,
            "self": "https://dev.dataloy.com/ws/rest/Action/1000009",
            "actionName": "EDIT"
        }
    ]
```

The endpoint AuditLog can be used to know all the objects that have been deleted:

[/ws/rest/AuditLog?filter=action.actionName(EQ)REMOVE](https://dev.dataloy.com/ws/rest/AuditLog?filter=action.actionName\(EQ\)REMOVE\&pageNumber=1\&limit=10\&filter=actionTime\(GT\)2024-02-01T21:48:22)

in combitation with other filters and the HTTP Header parameter **fields** with this value:

{"entryText":"\*","user":"\*","actionTime":"\*"}

return a response like this one:

```json
[
    {
        "key": 18475755,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475755",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:34",
        "entryText": "Deleted LaytimeTimeSheetItem #14707386"
    },
    {
        "key": 18475756,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475756",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:34",
        "entryText": "Deleted LaytimeTimeSheetItem #14707388"
    },
    {
        "key": 18475757,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475757",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:34",
        "entryText": "Deleted LaytimeTimeSheetItem #14707389"
    },
    {
        "key": 18475758,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475758",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:34",
        "entryText": "Deleted LaytimeTimeSheetItem #14707387"
    },
    {
        "key": 18475783,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475783",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:57",
        "entryText": "Deleted LaytimeTimeSheetItem #18475759"
    },
    {
        "key": 18475784,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475784",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:57",
        "entryText": "Deleted LaytimeTimeSheetItem #18475760"
    },
    {
        "key": 18475785,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475785",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:37:57",
        "entryText": "Deleted LaytimeTimeSheetItem #18475761"
    },
    {
        "key": 18475802,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475802",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:38:04",
        "entryText": "Deleted LaytimeTimeSheetItem #18475780"
    },
    {
        "key": 18475803,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475803",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:38:04",
        "entryText": "Deleted LaytimeTimeSheetItem #18475781"
    },
    {
        "key": 18475804,
        "self": "https://dev.dataloy.com/ws/rest/AuditLog/18475804",
        "user": {
            "key": 2527205,
            "self": "https://dev.dataloy.com/ws/rest/User/2527205"
        },
        "actionTime": "2024-02-02T08:38:04",
        "entryText": "Deleted LaytimeTimeSheetItem #18475782"
    }
]
```

where in the field entryText there is the object type and object key that has been deleted-


# Webhook Notification Retry Rules

When a webhook notification fails to deliver, the system will automatically retry based on the following rules.

#### Retry Schedule

Retries use an exponential backoff strategy. The delay between each retry attempt increases as follows:

<table data-search="false"><thead><tr><th>Attempt</th><th>Delay before retry</th></tr></thead><tbody><tr><td>1</td><td>Immediate</td></tr><tr><td>2</td><td>1 minute</td></tr><tr><td>3</td><td>2 minutes</td></tr><tr><td>4</td><td>5 minutes</td></tr><tr><td>5</td><td>10 minutes</td></tr><tr><td>6</td><td>15 minutes</td></tr><tr><td>7</td><td>30 minutes</td></tr><tr><td>8</td><td>1 hour</td></tr><tr><td>9</td><td>6 hours</td></tr><tr><td>10+</td><td>1 day</td></tr></tbody></table>

#### Maximum Attempts

The maximum number of retry attempts is controlled by the system setting `System.webhookAttempts`. This applies to all subscriptions, including those with "Do Not Unsubscribe" enabled. When the maximum is reached, the individual notification stops retrying, but the subscription remains active for new notifications.

#### Non-Retryable Errors

Notifications that fail with the following HTTP status codes are never retried, as these indicate permanent errors that will not resolve on their own:

<table data-search="false"><thead><tr><th>HTTP Status Code</th><th>Meaning</th></tr></thead><tbody><tr><td>400</td><td>Bad Request</td></tr><tr><td>401</td><td>Unauthorized</td></tr><tr><td>403</td><td>Forbidden</td></tr><tr><td>404</td><td>Not Found</td></tr><tr><td>405</td><td>Method Not Allowed</td></tr><tr><td>413</td><td>Payload Too Large</td></tr><tr><td>422</td><td>Unprocessable Entity</td></tr></tbody></table>

All other errors are retried, including:

* Connection timeouts (endpoint unreachable)
* Server errors (5xx)
* Rate limiting (429)
* Request timeouts (408)
* Conflicts (409)

#### Circuit Breaker

If a notification fails for a subscription during a retry cycle, all remaining pending notifications for that same subscription are skipped in that cycle. This prevents the system from repeatedly hitting a known failing endpoint. Skipped notifications are not counted as attempts — they will be picked up in the next cycle.

#### HTTP Timeouts

Webhook HTTP calls use configurable timeouts to prevent indefinite blocking:

| Setting    | Description                                              | Default    |
| ---------- | -------------------------------------------------------- | ---------- |
| `CTIMEOUT` | Connect timeout — maximum time to establish a connection | 15 seconds |
| `RTIMEOUT` | Read timeout — maximum time to wait for a response       | 60 seconds |

These can be configured via System Preferences.

#### Overlap Protection

If a retry cycle takes longer than the timer interval, the next cycle will not start until the current one finishes. This prevents multiple retry cycles from running simultaneously.


# Accounting Integration API

**The objective of** accounting integration is to *automate the creation and flow of transactions between the Dataloy VMS and an accounting system*. The advantage is, for example, reduced risk of errors as several transactions handled by the Dataloy VMS system generates transactions to be entered in a client accounting system. An integration also allows for synchronizing the basic data entities (or [*Master Data*](/api-release-8.25/dataloy-rest-api/master-data-objects)*, i.e. several of the same being stored and maintained in both systems*) between systems. Some Master Data, for example, Business Partners, must be synchronized for the integration to work.

## **Accounting Integration Transactions**

#### **Transactions from Dataloy VMS to Accounting:**

* Sales and purchase invoices are transferred whenever an invoice/invoices is/are posted in the VMS.
* Bunker transactions are transferred whenever a bunker transaction is posted in the VMS.
* Vessel/Voyage information is sometimes required by Accounting before invoices and/or bunker transactions are transferred. A scheduled task for transferring this type of information to Accounting can be set up (contact Dataloy for more information).
* Accruals will be transferred by users when performing period-end-closing (*more information:* [*Accruals*](https://docs.dataloy.com/voyage-management-system/step-by-step-guides/finance/accruals) *page and the* [*Period-End-Closing*](https://docs.dataloy.com/voyage-management-system/step-by-step-guides/finance/accruals/period-end-closing) *process*).

#### **Transactions from Accounting to Dataloy VMS:**

* Receipts and payments being transferred from Accounting to Dataloy VMS. The transaction to collect and payments and send to the VMS is either triggered by Accounting or by a scheduled task (set up by Dataloy Systems).
* Exchange rates will be transferred from Accounting to Dataloy VMS. This transaction is either triggered by Accounting or by a scheduled task (set up by Dataloy Systems) to collect and retrieve the rates.
* Actuals is part of the [Period-End-Closing process](https://docs.dataloy.com/voyage-management-system/step-by-step-guides/finance/accruals/period-end-closing) and is usually transferred from Accounting to Dataloy VMS.


# Invoicing

## **Prerequisites**

Certain integrations need to be in place before the set-up and testing of an invoice integration:

* Transfer of voyage related data to the accounting system.
* Synchronization of business partners between Dataloy VMS and the accounting system.
* Exchange rate transfer to Dataloy VMS.
* Map accounts between Dataloy VMS and the accounting system.

## **Integration Set-Up**

When invoices are posted in Dataloy VMS, the document status is automatically set to Ready-for-Posting. Set up a scheduled task and use the request under Data Transaction to extract invoices and credit notes that are ready for posting. When an invoice is transferred to accounting, update the status to Posted.

## **Dissolve or Reverse Invoice**

**To dissolve an assembled invoice** you need the document key and PUT as in the example below.

```
PUT /Document/{document key}
payload: {"invoicingStatus": "PEN"}
```

**To reverse a posted invoice** you need the document key and POST as in the example below.

```
POST /Document/{document key}/reverse
```

## Fetching invoice PDF

To fetch the PDF of a invoice, you will need the document key and perform a GET while having the field "invoice" as a part of the [fields-header](/api-release-8.25/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request#customize-the-number-of-fields-returned).

```
GET /Document/{document key}
fields: {"invoice": "*"}
```

{% hint style="warning" %}
The field "invoicePdf" is deprecated, and will not return any data.
{% endhint %}

{% hint style="info" %}
Only documents of type Invoice In, Invoice Out, Credit In, Credit Out and Advance Payment Req can be printed as PDF.
{% endhint %}

## **Data Transaction**

To get invoices that are ready for posting in [Webhooks](/api-release-8.25/dataloy-rest-api/webhooks) the following subscription can be created:

```
{
    "eventType":"U",
    "user": the user code to be used in the subscription,
    "objectType":"Document",
    "expression": "{"type":"group","id":"root","combine":"AND","items":[{"type":"condition","condition":{"id":"1782899454626-5vnfvqj","operator":"=","leftKind":"field","leftField":{"path":["invoicingStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"RFP"}},{"type":"group","id":"1782899467613-rlwidiv","combine":"OR","items":[{"type":"condition","condition":{"id":"1782899467613-0g14c7c","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"INO"}},{"type":"condition","condition":{"id":"1782899471039-tyeclsh","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"INI"}},{"type":"condition","condition":{"id":"1782899471428-5j3jh9q","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"CRI"}},{"type":"condition","condition":{"id":"1782899471816-cjdikzr","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"CRO"}}]}],"version":2}",
    "url": "your webhook url"
}
```

The expression logic if you want to use the expression builder: invoicingStatus.statusTypeCode = "RFP" AND (documentType.documentType = "INO" OR documentType.documentType = "INI" OR documentType.documentType = "CRI" OR documentType.documentType = "CRO")

Alternatively, a scheduled job can be set-up to use the following request:

### **Get invoices that are ready for posting to accounting**

| `GET /Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&filter=documentType.documentType(IN)(INI,INO,CRI,CRO)` |
| ------------------------------------------------------------------------------------------------------------------ |

### **Payment Terms**

There will be only one Document object in the API despite two payment terms for an invoice (for example 95/5 percent). However, the Document will have two documentPaymentTerms objects in the Document.documentPaymentTerms list.

To create two documents when integrating:

1. Loop on paymentTerms and create one document for each payment term.
2. Calculate the following values:
   * *dueDate*: document.documentPaymentTerms.dueDate
   * *documentAmount*: document.documentAmount \* document.documentPaymentTerms.percentage / 100
   * *companyCurrencyAmount*: document.companyCurrencyAmount \* document.documentPaymentTerms.percentage / 100
   * *sourceCurrencyAmount*: document.sourceCurrencyAmount \* document.documentPaymentTerms.percentage / 100

### **Test Data**

Test data for invoicing integration can be generated in the Dataloy VMS finance module (Accounts Receivable, Accounts Payable and Hire Payable).

### **Post Transaction**&#x20;

When an invoice is successfully transferred to an accounting system, the document status must be updated to *Posted* in Dataloy VMS. This is done in a PUT request:

```
PUT request on /Document/{key}
  
{
    "invoicingStatus": "POS"
}
```


# Payments/Receipts

## **Integration Set-Up**

When a payment is registered in the accounting system, it should be transferred as applicable to the *Posted* sections of either the Accounts Payable or the Accounts Receivable modules (where the matching invoice(s) can be found) in Dataloy VMS.

Since a payment in accounting systems may cover multiple Dataloy VMS payments/receipts, extracting payments from accounting means extracting invoices matching to a payment. Only payments/receipts records with a matching invoice in the applicable accounting system and with a required reference to a Dataloy invoice are to be extracted.

In Dataloy VMS all payments must match with the referenced invoice. To insert a payment/receipt in Dataloy VMS use the request under Data Transaction (below).

## **Data Transaction**

* A payment record should ONLY ever have one document line. Never more.

## **Amount Prefix**

This matrix is showing which prefix the payment amount should have for the various cases.

| <p><br></p>   | Accounts Payable and Hire Payable | Accounts Receivable |
| ------------- | --------------------------------- | ------------------- |
| Receipt (PMI) | Positive Amount                   | Negative amount     |
| Payment (PMO) | Negative Amount                   | Positive Amount     |

## **To Post a Payment/Receipt to Dataloy VMS:**

```
{
    "documentAmount": 10000.00,
    "companyCurrencyAmount": 10000.00,
    "sourceCurrencyAmount": 10000.00,
    "documentCurrency": "USD",
    "documentDate": "2014-01-01T00:00:00",
    "documentType": "PMO",
    "documentNo": "111111199",
    "externalDocumentNo": "50300",
    "company": "01",
    "businessPartner": "60526",
    "invoicingStatus": "POS",   
    "documentText": "text here",
    "documentLines":
    [
        {
            "documentAmount": 10000.00,
            "companyCurrencyAmount": 10000.00,
            "sourceCurrencyAmount": 10000.00,
            "documentCurrency": "USD",
            "invoicingStatus": "POS",
            "documentLineText": "text here",
            "businessPartner": "BPCODE",
            "isAccountsPayable": true,
            "refDocument": "71800125"
        }
    ]   
}
```


# Voyages

## **Prerequisites**

No prerequisites.

## **Integration Set-Up**

Accounting systems often require voyage related data before transferring accounting related transactions. Set up a scheduled task and use the request under [#data-transaction](#data-transaction "mention") to gather all voyages that has been modified since the last time a scheduled task was run.

## **Test Data**

Modify some existing voyages in the Booking and Operations module for testing, for example, changing a date in the schedule (***note**: changing dates will also affect the schedule for other voyages*).

## **Data Transaction**

### Get new voyages using webhooks

To get new voyages in [Webhooks](/api-release-8.25/dataloy-rest-api/webhooks) the following subscription can be created:

```
{
"eventType": "U",
"user":
"objectType": "VoyageHeader",
"expression": "{"type":"group","id":"root","combine":"OR","items":[{"type":"group","id":"1779183625231-nrms8uv","combine":"AND","items":[{"type":"condition","condition":{"id":"1779183625231-ctl7zhz","operator":"=","leftKind":"field","leftField":{"path":["voyageStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"previous","rightKind":"literal","rightValue":"EST"}},{"type":"condition","condition":{"id":"1779183710793-qsn8j3m","operator":"=","leftKind":"field","leftField":{"path":["voyageStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"NOM"}}]},{"type":"group","id":"1779183632027-tr8y79a","combine":"AND","items":[{"type":"condition","condition":{"id":"1779183632027-z9d3dbj","operator":"null","leftKind":"field","leftField":{"path":["referenceNo"],"type":"string","arrayFilters":[]},"leftSource":"previous","rightKind":"literal","rightValue":null}},{"type":"condition","condition":{"id":"1779183752798-06s1k61","operator":"notNull","leftKind":"field","leftField":{"path":["referenceNo"],"type":"string","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":null}},{"type":"condition","condition":{"id":"1779183769572-kl63bpk","operator":"=","leftKind":"field","leftField":{"path":["voyageStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"NOM"}}]}],"version":2}",
"url":
}
```

To get updated for all changes on a voyage the following webhook subscription can be created:

```
{
"eventType": "U",
"user":
"objectType": "VoyageHeader",
"url":
}
```

### **Get all fixed voyages modified since given date**

To extract all fixed voyages from Dataloy VMS that has been modified since a given date, use request below in conjunction with the base URL:

```
GET /VoyageHeader?filter=modifiedDate(GTE)2014-01-01T12:30:00
```

### **Post Transaction**&#x20;

No post transaction is required.


# Business Partners

## **Prerequisites**

Synchronization of business partners between Dataloy VMS and the applicable accounting system is required before transferring accounting related transactions. To synchronize business partner updates between systems, decide which system is to be the Master System (where the business partners will be updated). The Master System will then send updated business partner data to the other system.

## **Integration Set-Up**

* Dataloy VMS used as master:&#x20;
  * Dataloy recommends setting up up a [Webhook](/api-release-8.25/dataloy-rest-api/webhooks). As an alternative, setup a scheduled job and use the request under Data Transaction (below) to gather all business partners data having been modified since the last time a scheduled task was run.
* Dataloy VMS is *not* used as master: Use the requests under Data Transaction (below) to insert and update the business partners in Dataloy VMS.

## **Data Transaction**

### **Dataloy VMS as a master for business partners**

#### **Webhook**

Setup [Webhook subscriptions](/api-release-8.25/dataloy-rest-api/webhooks) for BusinessPartner, Address and ContactInfo. From Address and Contact info there is a reference back to the BusinessPartner key in the source field.

#### **Scheduled Job (If Webhook is not an option)**

Extract the business partners whose data has been modified since a selected date from Dataloy VMS using the following request in conjunction with the[ base URL](/api-release-8.25/dataloy-rest-api/getting-started):                                                                       &#x20;

#### **Get business partner information**

```
GET /BusinessPartner?filter=modifiedDate(GTE)2014-01-01T12:30:00
```

Set up a scheduled job and gather all voyages that have been modified since the last time a scheduled task was run.&#x20;

### **Other systems as Master for Business Partners**

Check if relevant business partner/s is/are already existing in Dataloy VMS by using the following request in conjunction with the base URL:                                                                                                   &#x20;

**Get business partner by key**

```
GET /BusinessPartner?filter=businessPartnerCode(EQ)99999
```

### If the business partner is already existing in Dataloy VMS

#### Update BusinessPartner

```
PUT /BusinessPartner
  
{
  "key": 1111111,
  "businessPartnerName": "Test Name",
  "businessPartnerCode": "123456789",
  "businessPartnerSort": "TESTNAME",
  "companyRegistrationNo": "123456789",
  "businessPartnerTypes": [
    {
      "businessPartnerType": "A"
    },
    {
      "businessPartnerType": "AU"
    }
  ],
  "bankAccounts": [
    {
      "key": 222222,
      "iban": "9754",
      "bankAccountNo": "6523",
      "bank": 1033615,
      "currency": 400132
    }
  ],
  "addresses": [
    {
      "key": 333333,
      "country": "NL",
      "address1": "Street Name 54",
      "address2": "5th floor",
      "address3": "",
      "city": "Amsterdam",
      "postalCode": "1000 AA"
    }
  ],
  "contactInfo": [
    {
      "key": 444444,
      "email": "test@test.com",
      "faxNo": "55555555",
      "mobileNo": "66666666",
      "phoneNo": "77777777",
      "telexNo": "88888888"
    }
  ]
}
```

### If the business partner does not exist in Dataloy VMS

[BusinessPartner API documentation](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/business-partner)

{% hint style="info" %}
***Note**: Use the Bank key if the Bank already exists. The below example is showing how to insert a new Bank when inserting a BusinessPartner*
{% endhint %}

```
POST /BusinessPartner

{
  "businessPartnerName": "Test Name",
  "businessPartnerCode": "123456789",
  "businessPartnerSort": "TESTNAME",
  "companyRegistrationNo": "123456789",
  "businessPartnerTypes": [
    {
      "businessPartnerType": "A"
    },
    {
      "businessPartnerType": "AU"
    }
  ],
  "bankAccounts": [
    {
      "iban": "9754",
      "bankAccountNo": "6523",
      "bank": {
        "bankName": "BP bank",
        "abaNumber": "1111",
        "chip": "2222",
        "swiftAddress": "42341"
      },
      "currency": 400132
    }
  ],
  "addresses": [
    {
      "country": "NL",
      "address1": "Street Name 54",
      "address2": "5th floor",
      "address3": "",
      "city": "Amsterdam",
      "postalCode": "1000 AA"
    }
  ],
  "contactInfo": [
    {
      "email": "test@test.com",
      "faxNo": "55555555",
      "mobileNo": "66666666",
      "phoneNo": "77777777",
      "telexNo": "88888888"
    }
  ]
}
```


# Exchange Rates

## P**rerequisites**

* An exchange rate source for extracting data to be inserted in Dataloy VMS.
* Base Currency must be set.\
  ***Note**: Locate Base Currency by getting ws/rest/System/1000000, then following relevant country link (Country Currency = the Base Currency).*

## **Integration Set-Up**

Set up a task for extracting exchange rates from either an accounting system or from a source delivering exchange rates service. Then insert the exchange rate into Dataloy VMS using the request under Data Transaction (below).

## **Data Transaction**

To insert an exchange rate in Dataloy VMS (fields required):

**Post an exchange rate to Dataloy**

```
POST /ExchangeRate
  
{
    "currency": "EUR",
    "fromCurrency": "USD",
    "exchangeRate": 0.74042,
    "exchangeRateDate": "2014-01-01T00:00:00"
}
```

### **Post Transaction**

No post transaction is required.


# Bunker Transactions

## **Prerequisites**

Before setting up and testing a bunker transaction integration other integrations need to be in place.

* [Transfer of voyage related data to the accounting system.](/api-release-8.25/user-guides/accounting-integration-api/voyages)
* [Synchronization of business partners between Dataloy VMS and the accounting system.](/api-release-8.25/user-guides/accounting-integration-api/business-partners)
* [Exchange rate transfer to Dataloy VMS.](/api-release-8.25/user-guides/accounting-integration-api/exchange-rates)

## **Integration Set-Up**

When a bunker transaction is posted in Dataloy VMS, the document status is set to Ready-for-Posting. Set up a scheduled task and use the request under Data Transaction to extract bunker transactions that are ready for posting. When a bunker transaction is transferred to accounting, update the status to Posted.

## **Test Data**

Test data for bunker transactions can be generated in Booking and Operations > Bunkers-FO tab > Bunker Transactions.

## **Data Transaction**

To get bunker transactions that are ready for posting in [Webhooks](/api-release-8.25/dataloy-rest-api/webhooks) the following subscription can be created:

```
{
    "eventType":"U",
    "user": the user code to be used in the subscription,
    "objectType":"Document",
    "expression": "{"type":"group","id":"root","combine":"AND","items":[{"type":"condition","condition":{"id":"1782903512505-wqx06zl","operator":"=","leftKind":"field","leftField":{"path":["invoicingStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"RFP"}},{"type":"condition","condition":{"id":"1782903524453-kmp0t03","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"ACC"}}],"version":2}",
    "url":"your webhook url"
}
```

If you use the expression builder, create an expression like this: invoicingStatus.statusTypeCode = "RFP" AND documentType.documentType = "ACC"

Alternatively a scheduled job can be setup to use the following request:

**Get bunker transactions that are ready for posting to accounting**

| `GET /Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&filter=documentType.documentType(EQ)ACC` |
| ---------------------------------------------------------------------------------------------------- |

### **Post Transaction**

When an invoice is successfully transferred to the accounting system, the document status has to be updated to *Posted* in Dataloy VMS. This is done in a PUT request:

**Update status to posted for a specific invoice**

```
PUT /Document/{key}
  
{
    "invoicingStatus": "POS"
}
```


# Actuals

## **Prerequisites**

[Invoice Integration ](/api-release-8.25/user-guides/accounting-integration-api/invoicing)needs to be in place before setting up and testing actuals integration.

## **Integration Set-Up**

Transfer of actuals (*or physicals*) from Accounting to Dataloy VMS can either be setup as a manual task through the Period-End-Closing Process or as a scheduled task. *Actuals* in accounting are actual costs and revenues, and once entered into Dataloy VMS, the actual record will appear in the Posted section of the Accruals module. Bunker transactions in Accounting that has been transferred from Dataloy VMS are not to be transferred, as they are already treated as actuals in Dataloy VMS (more information: actuals and accruals page and the Period-End-Closing process.

## **Data Transaction**

To insert an actual in Dataloy VMS:

* An actual record should ONLY ever have one document line. Never more.
* The document date should be the first day of the period month.
* Client can choose to insert actuals one by one or group actuals by period, currency, voyage, account and company
* Set a unique document number (*documentNo*).

Use request:

**Post an actual to Dataloy**

```
POST /Document
  
{
    "documentAmount": 10000.00,
    "companyCurrencyAmount": 10000.00,
    "sourceCurrencyAmount": 10000.00,
    "documentDate": "2014-01-01T00:00:00",
    "documentType": "ACC",
    "documentNo": "111111187",
    "company": "01",
    "invoicingStatus": "POS",
    "documentCurrency": "USD",
    "documentText": "text here",
    "glAccount": "1000",
    "documentLines":
    [
        {
            "documentAmount": 10000.00,
            "companyCurrencyAmount": 10000.00,
            "sourceCurrencyAmount": 10000.00,
            "documentCurrency": "USD",
            "exchangeRate": 1,
            "invoicingStatus": "POS",
            "documentLineText": "text here",
            "voyage": "VOY100",
            "glAccount": "1000"
        }
    ]
}
```

### Post Transaction

No post transaction is required.

<br>


# Autopost Invoices

When inserting data that in the end will result in an account payable, you might want to post the invoice directly. This can be done with a couple of API calls.

## Generate Invoice Lines

To generate invoice lines you need to know the key of the voyage that your data relates to. If you dont have the voyage key already you need to get it from the API either by getting it at an earlier stage in your integration or with a separate call in this stage. If you for instance already have the port call key you can get the voyage key by doing a GET request on PortCall.

To generate invoice lines post the below request, where key is the voyage key. For multiple voyages, add multiple keys.

```
POST /ws/rest/Document/refreshDocumentLines?key=123&key=456&isAccountsPayable=true
Body: empty

To locate the voyage key for Service Order and Bunker Order:

Service Order:
GET /ws/rest/ServiceOrder/{key}
Http header:
fields: {"portCall": {"voyage": {"key":"*"}}}

Bunker Order:
GET /ws/rest/BunkerOrder/{key}
Http header:
fields: {"portCall": {"voyage": {"key":"*"}}}
```

Then get the new invoice lines, called document lines in the API

```
Service Orders:
GET /ws/rest/DocumentLine?filter=voyage(IN)(123,456)&filter=document(NULL)
&filter=invoicingStatus.statusTypeCode(EQ)PEN&filter=portCall.key(EQ)118616134&filter=portCost.portAgent.daReference(EQ)DA-123

Bunker Orders:
GET /ws/rest/DocumentLine?filter=voyage(IN)(7173894)&filter=document(NULL)
&filter=invoicingStatus.statusTypeCode(EQ)PEN&filter=portCall.key(EQ)7173995
&filter=bunkerOrderLine.bunkerOrder.key(EQ)8366819
```

## Get invoice defaults (optional)

The below endpoint will give you data that can be used when assembling the invoice. Like bank account, issuing company and so on. If you already have the data you can skip this step.

```
POST /ws/rest/Document/invoiceDefaults

Header: disablebl = true (only for jvms customers)

Body:
{"documentLines":[{"key":111},{"key":222}], "invoicingStatus": "PEN"}
```

## Assemble invoice

Assemble the invoice with this request

```
POST /ws/rest/Document/assemble

Header: disablebl = true (only for jvms customers)

​​{
    "bankAccount": "bankAccountNo",
    "businessPartner": "businessPartnerCode",
    "documentCurrency": "USD",
    "documentDate": "2022-02-23T00:00:00",
    "documentLines": [{ "key": 111 }, { "key": 222 }],
    "documentPaymentTerms": [
        {
            "baselineDate": "2022-02-23T00:00:00",
            "baselineTerm": "baselineTermCode",
            "dueDate": "2022-03-02T00:00:00",
            "paymentTerms": "paymentTermsCode",
            "percentage": 100
        }
    ],
    "documentText": "A document text",
    "exchangeRate": 1,
    "exchangeRateDate": "2022-02-23T09:28:26",
    "externalDocumentNo": "1234",
    "issuingCompany": "companyCode",
    "invoicingStatus" : "INV"
}
```

* Mandatory fields: documentText, documentDate, issuingCompany, bankAccount, baseLineDate, baseLineTerms, dueDate, paymentTerms and percentage.
* If payment terms percentage is 100%, there should only be one entry in documentPaymentTerms
* BaseLineTerm is customer specific and needs to be agreed with customer. The baseline terms can be found at /ws/rest/BaselineTerm
* PaymentTerms is customer specific and needs to be agreed with customer. The payment terms can be found at /ws/rest/PaymentTerms

The request will return the new invoice, called Document in the API. Keep the Document key to post the document in next step.

## Post invoice

The final request will set the status to ready for posting which will cause accounting integrations to pick up the invoice and transfer it to accounting. The Document key is returned the assemble response in previous step.

```
PUT /ws/rest/Document/789

Header: disablebl = true (only for jvms customers)

{"invoicingStatus":"RFP"}
```


# Accruals

## **Prerequisites**

Before setting up and testing an invoice integration other integrations need to be in place:

* [Invoice Integration](/api-release-8.25/user-guides/accounting-integration-api/invoicing)
* [Actuals Integration](/api-release-8.25/user-guides/accounting-integration-api/actuals-1)

## **Integration Set-Up**

When accruals have been verified and posted in Dataloy VMS, the document status is set to *Ready-for-Posting*.

More information, go to Accruals and Period-End-Closing.

## **Data Transactions**

### **Get accruals and accrual reversals that are ready for posting to accounting**

To get accruals that are ready for posting in [Webhooks](/api-release-8.25/dataloy-rest-api/webhooks) the following subscription can be created:

```
{
    "eventType":"U",
    "user": the user code to be used in the subscription,
    "objectType":"Document",
    "expression": "{"type":"group","id":"root","combine":"AND","items":[{"type":"condition","condition":{"id":"1782903975402-box7vo7","operator":"=","leftKind":"field","leftField":{"path":["invoicingStatus","statusTypeCode"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"RFP"}},{"type":"group","id":"1782903976004-c70ukle","combine":"OR","items":[{"type":"condition","condition":{"id":"1782903976004-ncwqszm","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"ACP"}},{"type":"condition","condition":{"id":"1782903996392-x0fuak4","operator":"=","leftKind":"field","leftField":{"path":["documentType","documentType"],"type":"object","arrayFilters":[]},"leftSource":"current","rightKind":"literal","rightValue":"ACR"}}]}],"version":2}",
    "url":"your webhook url"
}
```

If you use the expression builder, create an expression like this: invoicingStatus.statusTypeCode = "RFP" AND (documentType.documentType = "ACP" OR documentType.documentType = "ACR")\
\
Alternativel&#x79;**,** a scheduled job can be setup to use the following request:

| `GET /Document?filter=invoicingStatus.statusTypeCode(EQ)RFP&filter=documentType.documentType(IN)ACP,ACR,CAP,CAR` |
| ---------------------------------------------------------------------------------------------------------------- |

### **Test Data**

Test data for accruals integration can be generated in the Accruals module in Dataloy VMS. Generate and batch post the accruals.

### **Post Transaction** &#x20;

When an accrual is successfully transferred to an accounting system, the accrual status must to be updated to *Posted* in Dataloy VMS. This is done in a PUT request:&#x20;

**Update status to posted for a specific invoice**

```
PUT /Document/{key}
  
{
    "invoicingStatus": "POS"
}
```


# Additional information

## **List of Document Statuses in Dataloy VMS**

| Document Status Code | Document Status Description | Description                                                                                                                                                                                                  |
| -------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| PEN                  | Pending                     | <p>Invoice is in the Pending section of either Accounts Payable  (AP), Accounts Receivable (AR) or Hire Payable (HP)<br>in Dataloy VMS.</p>                                                                  |
| INV                  | Approval                    | <p>Invoice is in the Assembled section of either Accounts Payable  (AP), Accounts Receivable (AR) or Hire Payable (HP)<br>in Dataloy VMS.</p>                                                                |
| RFP                  | Ready-For-Posting           | <p>Invoice is in the Posted section section of either Accounts Payable  (AP), Accounts Receivable (AR) or Hire Payable (HP)<br>in Dataloy VMS, but has not yet been transferred to an accounting system.</p> |
| POS                  | Posted                      | <p>Invoice is in Posted section of either Accounts Payable  (AP), Accounts Receivable (AR) or Hire Payable (HP)<br>in Dataloy VMS and has been transferred to an accounting system.</p>                      |

## **List of Document Line Fields**

| Field Name                     | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Not possible to user in filters |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| documentAmount                 | <ul><li>For /DocumentTypes INO, INI, CRI, CRO: Amount in order currency/sales currency. The original currency.</li><li>For /DocumentTypes PMI, PMO: Amount in Invoice Currency.</li><li>For /DocumentTypes ACR, ACP: Amount in Voyage Currency.</li><li>For /DocumentTypes APR: Amount in Advance Currency</li><li>For /DocumentTypes ACC: Amount in Invoice Currency (use Voyage currency if Invoice Currency is not present)</li></ul>                                                                                                                                                                                                                   |                                 |
| companyCurrencyAmount          | For all /DocumentTypes : Amount in Company Currency for the Document.Company.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |                                 |
| sourceCurrencyAmount           | <ul><li>For /DocumentTypes INO, INI, CRI, CRO: Amount in order currency/sales currency. The original currency.</li><li>For /DocumentTypes PMI, PMO: Amount in Original Payment Currency.</li><li>For /DocumentTypes ACR, ACP: Amount in Voyage Currency.</li><li>For /DocumentTypes APR: Amount in Advance Currency</li><li>For /DocumentTypes ACC: Amount in Voyage Currency</li></ul>                                                                                                                                                                                                                                                                    |                                 |
| documentCurrency.currencyCode  | Currency Code for documentAmount. More information, see documentAmount                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |                                 |
| sourceCurrencyCode             | Currency code for sourceCurrencyAmount. More information see sourceCurrencyAmount                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |                                 |
| exchangeRate                   | Exchange Rate between documentAmount and sourceCurrencyAmount                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |                                 |
| exchangeRateDate               | Exchange Rate Date                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |                                 |
| glAccount                      | General Ledger Account                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | X                               |
| quantity                       | <p>Has Different Meaning Depending on Document Type:<br></p><ul><li>Accruals - <em>Onhire Days Within Accrual Period</em></li><li>Bunkers - <em>Bunker Quantity</em></li><li>Freight - <em>Cargo Quantity</em></li><li>Charter Hire - <em>Days</em></li><li>Meals and Cables - <em>Days</em></li><li>VAT - <em>VAT Amount is Quantity \* vatRate</em></li><li>Various, Days - <em>Voyage Days</em></li><li>Various, Rate - <em>Cargo Quantity</em></li><li>Offhire - <em>Offhire Days</em></li><li>Deadfreight - <em>Deadfreight Quantity</em></li><li>Demurrage/Despatch - <em>Days</em></li></ul>                                                        |                                 |
| unitPrice                      | Unit Price. Quantity \* Unit Price = Document Amount                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |                                 |
| invoicingStatus.statusTypeCode | Status Code, see [Document Status List](#list-of-document-statuses-in-dataloy-vms)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |                                 |
| documentLineText               | Document Line Text/Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |                                 |
| businessPartner                | <p>Business Partner Object. (Value: businessPartnerCode or businessPartner Key).</p><p>Invoice and Payment/Receipt:</p><ul><li><p>Outgoing invoice:</p><ul><li>document.company is the company in Dataloy VMS issuing the invoice.</li><li>document.businessPartner is the business partner receiving the invoice.</li><li>On the referring payment, document.company is receiving the payment.</li></ul></li><li><p>Incoming invoice:</p><ul><li>document.businessPartner is issuing the invoice.</li><li>document.company is receiving the invoice.</li><li>On the referring payment document.company is the one paying the invoice.</li></ul></li></ul> |                                 |
| isAccountsPayable              | <p>false = Accounts Receivable, true = Accounts Payable<br><br>Inserting Payment/Receipt:<br>For payments referring to Accounts Receivable invoices set value to 0. For payments referring to Accounts Payable invoice set value to 1. This value should always have the same value as for the referring invoice.</p>                                                                                                                                                                                                                                                                                                                                      |                                 |
| refDocument                    | <p>Referring Document for Reversals, Payments and Receipts. To set refDocument use Document Number or Key.</p><p>Payment/Receipts: Setting refDocument for payment receipts, documentLine.voyage will be set equal to the documentLine.voyage of the referring invoice.</p>                                                                                                                                                                                                                                                                                                                                                                                |                                 |
| vatRate.vatRate                | VAT Rate                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |                                 |
| vatRate.vat.vatCode            | VAT Code                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |                                 |
| freightRate                    | Freight Rate Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |                                 |
| portCall                       | portCall Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |                                 |
| handlingCost                   | handlingCost Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |                                 |
| businessUnit                   | businessUnit Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |                                 |
| account                        | Account Object, use glAccount instead                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |                                 |
| handlingCostCode               | handlingCostCode Object, use glAccount instead                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |                                 |
| billOfLading                   | billOfLading Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |                                 |
| claim                          | Claim Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |                                 |
| offhire                        | Offhire Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |                                 |
| voyage                         | Voyage Object                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |                                 |

## **Bank Fields List**

| Field Name                                                                                       | Description  | Required | Unique | Not Possible to Set in Filters |
| ------------------------------------------------------------------------------------------------ | ------------ | -------- | ------ | ------------------------------ |
| bankName                                                                                         | Bank Name    | Yes      |        |                                |
| swiftAddress                                                                                     | SWIFT Code   | Yes      | Yes    |                                |
| chip                                                                                             | Chip ID      |          |        |                                |
| abaNumber                                                                                        | ABA Code     |          |        |                                |
| [addresses](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/address)        | Address      |          |        | X                              |
| [contactInfo](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/contact-info) | Contact Info |          |        | X                              |


# Schedule API

Create a Voyage with a Loading and Discharging PortCall with one Cargo with a Loading and Discharging CargoPort.&#x20;

&#x20;

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre class="language-json"><code class="lang-json">POST /Voyage

{
"ballastPort":102546,
"vessel":1609791,
"cargos":\[
{
"cargoMeasurement":"MT",
"cargoType":"SPOT",
"cargoPorts":\[
{
"cargoPortSequence":1,
"port":105219,
"reasonForCall":"L"
},
{
"cargoPortSequence":1,
"port":101770,
"reasonForCall":"D"
}
]
}
],
"portCallsFromVoyage":\[
{
"port":105219,
"portCallSequence":1,
"reasonForCall":"L",
"currency":"EUR"
},
{
"port":101770,
"portCallSequence":2,
"reasonForCall":"D",
"currency":"EUR"
}
]
} </code></pre></td></tr></tbody></table>

The created voyage will get the status Estimated (code EST).

Creating a new Cargo with a Loading and Discharging CargoPort and PortCall. The PortCall objects have EventLogDates that specify Arrival, Berthing, Un-berthing, and Departure dates.

```json
POST /Cargo
 
{
    "cargoMeasurement": "MT",
    "cargoPorts": [
        {
            "cargoPortSequence": 1,
            "cargoQuantity": 1234,
            "laytimeTermsMeasurement": "H",
            "port": {
                "key": 102381
            },
            "portCall": {
                "portCallSequence": 3,
                "reasonForCall": "L",
                "port": 102381,
                "voyage": 6136896
            },
            "reasonForCall": "L"
        },
        {
            "cargoPortSequence": 1,
            "cargoQuantity": 1234,
            "freightRate": 1210,
            "laytimeTermsMeasurement": "H",
            "port": {
                "key": 101486
            },
            "portCall": {
                "portCallSequence": 4,
                "reasonForCall": "D",
                "port": 101486,
                "voyage": 6136896
            },
            "reasonForCall": "D"
        }
    ],
    "charterer": {
        "key": 1004307
    },
    "commodity": {
        "key": 1675975
    },
    "freightCurrency": "USD",
    "voyage": {
        "key": 6136896
    }
}
```

Adding to a Cargo a new Loading or Discharging CargoPort and PortCall

```json
PUT /Cargo/{KEY}
 
{
    "cargoPorts": [
        {
            "key": 18739785
        },
        {
            "key": 18739786
        },
        {
            "port": 103991,
            "reasonForCall": "D",
            "cargoPortSequence": 2,
            "portCall": {
                "portCallSequence": 6,
                "reasonForCall": "D",
                "port": 103991,
                "voyage": 18739534,
                "ownedByVoyage": 18739534
            }
        }
    ]
}

```

Fixing the date on an EventLog object. Note, only EventLogs with EventLog.EventLogDate from the past can be fixed, otherwise, the returned value of isDateFixed will be *false*.

```json
PUT /EventLog/{KEY}

{
    "isDateFixed":true
}
```

### Nominate an estimate voyage

To nominate a voyage of a given vessel first you need to get the last sequence for the vessel in the fleet plan:

```
GET https://dev.dataloy.com/ws/rest/Voyage?filter=vessel(EQ)1609791&fleetPlanVoyages.fleetPlan.fleetPlanCode(EQ)MASTER&filter=voyageHeader.voyageStatus.statusTypeCode(NE)EST&sort=fleetPlanVoyages.sequence(DS)
```

sending the HTTP Header property **fileds** withi this value:

`{"fleetPlanVoyages":{"sequence":"*"}}`

Then you can nominate the voyage making a PUT sending this payload:

```json
{
   "key":76409955,
   "voyageHeader":{
      "key":76409960,
      "voyageStatus":"NOM",
      "isVoyageStartFixed":false,
      "isEstimate":false,
      "isUnallocated":false
   },
   "fleetPlanVoyages":[
      {
         "fleetPlan":"MASTER",
         "voyage":76409955,
         "sequence":11,
         "vessel":1609791
      }
   ]
}
```

incrementing the sequence by 1.


# Bunker Order Integration API


# Service Order Integration API

**The objective of** the Service Order integration is to trigger the ordering of port related services and receive updates on estimated, revised and actual cost from parties handling the orders. The costs are internally assigned to the correct port call, vessel and voyage and processed further inside the VMS.

### Description

***Note**: Recommended before proceeding - read: Getting Started with Dataloy REST API.*

The endpoints for the Port Service Order process are:

1. [ServiceCode](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-code).
2. [ServiceOrder](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-order).
3. [ServiceOrderLine](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-order-line).

ServiceOrder objects are created by Dataloy VMS with the status Draft,  status code **DFT**.

The integration should use *Webhooks* to be notified when a new ServiceOrder object is created.

POST.WebhookSubscription:

```json
     {
        "user":  12345679,
        "channelInfo": {
            "url": "https://push.here.com",
            "channelType": "HTTP"
        },
        "eventType": "C",
        "objectType": "ServiceOrder"
    }
```

The JSON sent, when a service order is created, will have this structure:

```json
{
   "id":"0:ffff7f000001:-1c943d78:678f500d:42f06",
   "eventTime":"2025-01-22T07:41:46",
   "eventType":"C",
   "objectType":"ServiceOrder",
   "dataloyObject":69801182,
   "dataloyObjectSelf":"https://dev.dataloy.com/ws/rest/ServiceOrder/69801182",
   "subscription":{
      "key":69801122,
      "self":"https://dev.dataloy.com/ws/rest/WebhookSubscription/69801122"
   },
   "resource":{
      "key":69801182,
      "self":"https://dev.dataloy.com/ws/rest/ServiceOrder/69801182",
      "currency":{
         "key":400132,
         "self":"https://dev.dataloy.com/ws/rest/Currency/400132"
      },
      "status":{
         "key":51969046,
         "self":"https://dev.dataloy.com/ws/rest/StatusType/51969046"
      },
      "orderDate":"2024-05-18T20:22:00",
      "exchangeRate":1.0,
      "portAgentType":null,
      "portCall":{
         "key":69276170,
         "self":"https://dev.dataloy.com/ws/rest/PortCall/69276170"
      },
      "serviceOrderLines":[
         
      ],
      "amount":0.0,
      "amountAdvanced":0.0,
      "amountHandlingCost":0.0,
      "amountHandlingCostVoyageCurrency":0.0,
      "amountPortCost":0.0,
      "amountPortCostVoyageCurrency":0.0,
      "amountVariousCost":0.0,
      "amountVariousCostVoyageCurrency":0.0,
      "amountVoyageCurrency":0.0,
      "emailSentDate":null,
      "amountAdvancedCurrency":{
         "key":400132,
         "self":"https://dev.dataloy.com/ws/rest/Currency/400132"
      },
      "businessPartner":{
         "key":1318806,
         "self":"https://dev.dataloy.com/ws/rest/BusinessPartner/1318806"
      },
      "nominationEmail":null,
      "externalReferenceNo":"1737531705924",
      "createdById":66007605,
      "createdDate":"2025-01-22T07:41:45",
      "externalObjectKey":null,
      "modifiedDate":null,
      "changedById":66007605,
      "remarks":[
         
      ],
      "isObjectActive":true
   }
}
```

It is possible to be notified only by the raw object, in this case the WebhookSubscription has to have the following property:

```
"rawObject" : true
```

In this case the JSON sent will be like this:

```json
{
   "key":69801182,
   "self":"https://dev.dataloy.com/ws/rest/ServiceOrder/69801182",
   "currency":{
      "key":400132,
      "self":"https://dev.dataloy.com/ws/rest/Currency/400132"
   },
   "status":{
      "key":51969046,
      "self":"https://dev.dataloy.com/ws/rest/StatusType/51969046"
   },
   "orderDate":"2024-05-18T20:22:00",
   "exchangeRate":1.0,
   "portAgentType":null,
   "portCall":{
      "key":69276170,
      "self":"https://dev.dataloy.com/ws/rest/PortCall/69276170"
   },
   "serviceOrderLines":[
      
   ],
   "amount":0.0,
   "amountAdvanced":0.0,
   "amountHandlingCost":0.0,
   "amountHandlingCostVoyageCurrency":0.0,
   "amountPortCost":0.0,
   "amountPortCostVoyageCurrency":0.0,
   "amountVariousCost":0.0,
   "amountVariousCostVoyageCurrency":0.0,
   "amountVoyageCurrency":0.0,
   "emailSentDate":null,
   "amountAdvancedCurrency":{
      "key":400132,
      "self":"https://dev.dataloy.com/ws/rest/Currency/400132"
   },
   "businessPartner":{
      "key":1318806,
      "self":"https://dev.dataloy.com/ws/rest/BusinessPartner/1318806"
   },
   "nominationEmail":null,
   "externalReferenceNo":"1737531705924",
   "createdById":66007605,
   "createdDate":"2025-01-22T07:41:45",
   "externalObjectKey":null,
   "modifiedDate":null,
   "changedById":66007605,
   "remarks":[
      
   ],
   "isObjectActive":true
}
```

{% content-ref url="/pages/-MLgl845hNHAl9v20sym" %}
[Adjust Number of Fields to be Returned from a Request](/api-release-8.25/dataloy-rest-api/adjust-number-of-fields-to-be-returned-from-a-request)
{% endcontent-ref %}

The ***fields*** property to customize the messages must be encoded with Base64 and set in attribute ***json*** of the WebhookSubscription

If the integration want to be notified also when there are changes to the PortCall connected with the ServiceOrder, a WebhookSubscription like this should be POST:

```json
     {
        "user":  12345679,
        "channelInfo": {
            "url": "https://push.here.com",
            "channelType": "HTTP"
        },
        "eventType": "U",
        "objectType": "PortCall",
        "dataloyObject": 36344213
    }
```

where “dataloyObject“: 3644213 is the PortCall key.

The integration can change an existing Service Order through HTTP PUT, see [ServiceOrder](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-order), [ServiceOrderLine](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F7.1/model/schemas/service-order-line).

To add a new line to a a order:

PUT:[https://url/ws/rest/ServiceOrder/](https://millenary-test.dataloy.com/ws/rest/ServiceOrder/33851810){ServiceOrder\_key}

```json
{
    "serviceOrderLines": [
        {
            "amountEstimate": 200,
            "description": "first line",
            "isCharterersCost": false,
            "isOwnersCost": false,
            "serviceCode": "PRC"
        }
    ]
}

```

**Auto Posting of Invoices**

Auto posting of service order invoices is supported for integrations with external agency systems. This feature allows invoices to be automatically posted when service orders are updated via the API.

A key prerequisite is configuring the [**Auto Post Service Order** system setting](https://docs.dataloy.com/voyage-management-system/step-by-step-guides/setup/system-settings/general). This setting determines the service order status from which auto posting is enabled and includes invoicing properties such as *Default Payment Term* and *Default Baseline Term*.

Once configured, it's essential to include the `autoPost = true` HTTP header in all PUT requests to service orders and/or service order lines. This will trigger the automatic posting of the invoices based on the updated data.

**Important Note**

* **Manual Changes Will Not Trigger Auto Posting**
  * Changes made via the VMS client UI (manually by users) will NOT trigger auto posting. This feature is exclusive to API-based integrations.

{% code overflow="wrap" %}

```
PUT /ws/rest/ServiceOrder/6420123 HTTP/1.1
Host: localhost:8080
autoPost: true
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkVJWjlvcFlVZWZaLXVsbTk5SUpCTyJ9.eyJpc3MiOiJodHRwczovL2ludGVybmFsLmV1LmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw2NGY5ODE4MzU5OGI3YTg2ZjllZDUzMTAiLCJhdWQiOlsiaHR0cHM6Ly9kYXRhbG95LmludGVybmFsIiwiaHR0cHM6Ly9pbnRlcm5hbC5ldS5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNzEyMDU2MjIwLCJleHAiOjE3MTIwNjM0MjAsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJhenAiOiJadGZXVTdYZEJmaGtQb0pSNHhCelVGQlpKU1htbzlJdCJ9.ZU
Content-Length: 190

{"serviceOrderLines":[{"key":6420124,"amountEstimate":12501,"amountFinal":0,
"amountRevised":0,"description":null,"isCharterersCost":true,
"isOwnersCost":false,"serviceCode":{"key":6003979}}]}
```

{% endcode %}

**Service Order statues**

* Draft, DFT
* Estimated, EST
* Revised, REV
* Final, FIN
* Cancel, CAN

**Service Order status transitions**&#x20;

<figure><img src="/files/2GBlhN39ZakjW0A6azNa" alt=""><figcaption></figcaption></figure>

**Service Order status transitions when Agent nomination is enabled**&#x20;

<figure><img src="/files/SLQlC9942BDTVMWeN1AY" alt=""><figcaption></figcaption></figure>


# Vessel Report


# Overview

PositionReport is used to update the status of an ongoing voyage's port calls.

## Overview

Position reports update a port call's sailing, arrival, in port, and departure status. Most fields in the PositionReport object will only provide information, while a few affect the port call's results.

The following fields will affect the port call's results:

* eventLogs
  * An [**EventLog**](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log) captures port events along with their dates and times. The port events include ARRIVAL, BERTHED, UNBERTHED, and DEPARTURE. To record the arrival date of a port call, an event log entry should include the ARRIVAL event along with the corresponding date.

  * A [**PositionReportBunker**](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker) records the remaining bunkers on board for a specific bunker category.

    <br>

Fields impacting the port call's results will have **Major Change Factor** marked as yes, along with a description, on the [details](#details).

PositionReport can be one of these types:

* Noon Report
  * logs the ship's status at sea, updating the estimated arrival date and ROB info
* Arrival Report
  * logs when the ship arrives in the port, fixing the arrival date and ROB info
* Berth Report
  * logs when the ship has berthed in the port, fixing the berthed date and ROB info
* Unberth Report
  * logs when the ship has unberthed in the port, fixing the unberthed date and ROB info
* In Port Report
  * logs supplementary information such as hours in service, weather, wind direction and average wind direction when the ship is docked.&#x20;
* Departure Report
  * logs when the ship leaves the port, fixing the departure date and ROB info

In order to include a [Remark](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/remark) on the position report, a separate API request must be made after the report is created. See [here](#arrival-report-with-remark) for an example.

## Details

### Noon Report&#x20;

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="215">Json Attribute</th><th width="161">Description</th><th>Mandatory</th><th>Major Change Factor</th><th width="209">Data type</th><th>Notes</th></tr></thead><tbody><tr><td>Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"NOON"</td></tr><tr><td>Noon Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td>yes</td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Latitude</td><td><code>latitude</code></td><td>Current position</td><td>yes</td><td></td><td>Double</td><td></td></tr><tr><td>Longitude</td><td><code>longitude</code></td><td>Current position</td><td>yes</td><td></td><td>Double</td><td></td></tr><tr><td>Estimated Time of Arrival</td><td><code>eventLogs</code></td><td>Date and time of estimated time of arrival</td><td>yes</td><td>yes, updates PortCall's arrival date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's arrival event log</p><p><br>date should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":100}]</code></td><td>Remaining bunkers on board at the time of reporting for the given bunker category</td><td></td><td>yes, updates PortCall's arrival rob</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td>one PositionReportBunker object for each bunker category</td></tr><tr><td>Wind Direction</td><td><code>windDirection</code></td><td>Determines current wind direction</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/direction">Direction</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#direction-data">Click here for more details</a></td></tr><tr><td>Average Wind Force</td><td><code>averageWindForce</code></td><td>General wind conditions</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Sea Direction</td><td><code>seaDirection</code></td><td>Current sea direction</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/direction">Direction</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#direction-data">Click here for more details</a></td></tr><tr><td>Average Sea State</td><td><code>averageSeaState</code></td><td>General sea conditions</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Weather</td><td><code>weather</code></td><td>Determines current weather</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/weather">Weather</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#weather-data">Click here for more details</a></td></tr><tr><td>Distance Sailed</td><td><code>distanceSailed</code></td><td>Distance sailed</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Hours in Service</td><td><code>hoursInService</code></td><td>Number of hours in operation</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Main Engine RPM</td><td><code>rpmFromLastPort</code></td><td>RPM recorded from previous port</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Noon report example

<details>

<summary>Noon Report sailing to a port</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query and headers:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

An example of the response could be found [here](#portcall-query-with-eventlogs-fields-response)

2. Generate a Noon Report for the vessel that has sailed 3150 nm to the queried PortCall, with South/West wind direction and partly cloudy weather.  Arrival LS MGO robs are also updated to 250

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

{% code overflow="wrap" %}

```json
{
    "vesselReportType": "NOON",
    "reportDateLocal": "2024-08-01T19:00:00",
    "portCall": 123456, //key from the response of the PortCall query
    "latitude": 60.2139,
    "longitude": 4.5300,
    "eventLogs": [
        {
            "key": 123456, //arrival event log key
            "eventLogDate": "2024-08-02T02:36:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 555
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 7777
        
        }
    ],
    "windDirection": 911643,
    "weather": 950928,
    "distanceSailed": 3150.00
}
```

{% endcode %}

</details>

### Arrival Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="198">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"ARR"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Arrival Date</td><td><code>eventLogs</code></td><td>Date and time of arrival on port</td><td>yes</td><td>yes, updates and fixes PortCall's arrival date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's arrival event log</p><p><br>date should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Arrival Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Actual Distance Sailed Since Departure</td><td><code>distanceSailed</code></td><td>Distance in nm sailed from previous port</td><td></td><td>yes, updates the PortCall's actual distance sailed</td><td>Double</td><td></td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":98}]</code></td><td>Remaining bunkers at the time of arrival for the given bunker category</td><td></td><td>yes, updates and fixes PortCall's arrival ROB</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td>one PositionReportBunker object for each bunker category</td></tr><tr><td>Hours Stoppage</td><td><code>hoursStoppages</code></td><td>Number of hours in stoppage of operation</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Hours In Service</td><td><code>hoursInService</code></td><td>Number of hours in operation</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Speed Made Good</td><td><code>speedMadeGood</code></td><td>Net speed when sailing to the port</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Draft Aft</td><td><code>draftAft</code></td><td>Vessel's draft aft</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Draft Forward</td><td><code>draftForward</code></td><td>Vessel's draft forward</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Arrival report example

<details>

<summary>Arrival report on port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

Example of the response can be found [here](#portcall-query-with-eventlogs-fields-response)

2. Generate a report for arrival at 2nd August 2024 03:00 with arrival FO ROB at 225.85 mt and arrival LS MGO ROB at 235 mt

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "ARR",
    "reportDateLocal": "2024-08-01T19:00:00",
    "portCall": 123456, //key from the response of the PortCall query
    "latitude": 60.2139,
    "longitude": 4.5300,
    "eventLogs": [
        {
           "key": 123456, //arrival event log key
            "eventLogDate": "2024-08-02T03:00:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 235
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 225.85
        
        }
    ]
}
```

</details>

### Berth Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="214">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"BRT"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Berth date</td><td><code>eventLogs</code></td><td>Date and time of berthing on port</td><td>yes</td><td>yes, updates and fixes PortCall's berthed date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's berth event log</p><p><br>date should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Berth Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":95}]</code></td><td>Remaining bunkers at the time of berthing for the given bunker category</td><td></td><td>yes, updates and fixes PortCall's berthing ROB</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td><p>one PositionReportBunker object for each bunker category</p><h4 id="berth-report-example"><br></h4></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Berth report example

<details>

<summary>Berth report on a port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

2. Generate a report that has berthed 3rd August 2024 08:00 with berth FO rob at 225 mt and DL rob at 220 mt

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "BRT",
    "reportDateLocal": "2024-08-03T10:36:00",
    "portCall": 123456, //key from the response of the PortCall query
    "eventLogs": [
        {
            "key": 123456, //berth event log key
            "eventLogDate": "2024-08-03T10:36:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 220
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 225
        
        }
    ]
}
```

</details>

### Unberth Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="207">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"UBRT"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Unberth date</td><td><code>eventLogs</code></td><td>Date and time of berthing on port</td><td>yes</td><td>yes, updates and fixes PortCall's berthed date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's unberth event log</p><p><br>date should be in this format: "YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Unberth Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":95}]</code></td><td>Remaining bunkers at the time of unberthing for the given bunker category</td><td></td><td>yes, updates and fixes PortCall's unberthing ROB</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td><p>one PositionReportBunker object for each bunker category</p><h4 id="berth-report-example"><br></h4></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Unberth report example

<details>

<summary>Unberth report on a port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

Example response can be found [here](#portcall-query-with-eventlogs-fields-response)

2. Generate a report that has unberthed 5th August 2024 08:00, FO unberth ROB at 225 mt, DL unberth at 218.5 mt

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "UBRT",
    "reportDateLocal": "2024-08-05T08:00:00",
    "portCall": 123456, //key from the response of the PortCall query
    "eventLogs": [
        {
            "key": 123456, //unberth event log key
            "eventLogDate": "2024-08-05T08:00:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 218.5
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 225
        
        }
    ]
}
```

</details>

### In Port Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="198">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"PORT"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>In Port Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Hours In Service</td><td><code>hoursInService</code></td><td>Number of hours in operation</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Weather</td><td><code>weather</code></td><td>Current weather</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/weather">Weather</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#weather-data">Click here for more details</a></td></tr><tr><td>Wind Direction</td><td><code>windDirection</code></td><td>Current wind direction</td><td></td><td></td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/direction">Direction</a></td><td><a href="/pages/7WNtVUI6a9kCz1auFJDq#direction-data">Click here for more details</a></td></tr><tr><td>Average Wind Force</td><td><code>averageWindForce</code></td><td>General wind conditions</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### In port report example

<details>

<summary>In port report on a port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

2. Generate a report to log sunny weather, East wind direction, hours in service, average wind force status in port

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "PORT",
    "reportDateLocal": "2024-08-03T18:00:00",
    "portCall": 123456, //key from the response of the PortCall request
    "hoursInService": 225.85,
    "weather": 950927,
    "windDirection": 911638,
    "averageWindForce": 1
}
```

</details>

### Departure Report

<table data-full-width="true"><thead><tr><th>Field Name</th><th width="199">Json Attribute</th><th>Description</th><th>Mandatory</th><th>Major Change Factor</th><th>Data Type</th><th>Notes</th></tr></thead><tbody><tr><td>Vessel Report Type</td><td><code>vesselReportType</code></td><td>Determines the type of vessel report</td><td>yes</td><td></td><td>String</td><td>"DEP"</td></tr><tr><td>Port Call</td><td><code>portCall</code></td><td>Port to update</td><td>yes</td><td></td><td>Long</td><td>key of the port call</td></tr><tr><td>Departure date</td><td><code>eventLogs</code></td><td>Date and time of departure from port</td><td>yes</td><td>yes, updates and fixes PortCall's departure date</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/event-log">EventLog</a></td><td><p>should be the key of the port call's departure event log</p><p><br>date should be in this format: "YYYY-MM-DDTHH:mm:ss"</p></td></tr><tr><td>Departure Report Date</td><td><code>reportDateLocal</code></td><td>Date and time of creation of the report</td><td></td><td></td><td>String</td><td>should be in this format:<br>"YYYY-MM-DDTHH:mm:ss"</td></tr><tr><td>Remaining bunkers on board</td><td><code>"positionReportBunkers": [{"bunkerCategory": "FO", "rob":90}]</code></td><td>Remaining bunkers at the time of departure for the given bunker category</td><td></td><td>yes, updates and fixes PortCall's departure ROB</td><td><a href="https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/position-report-bunker">PositionReportBunker</a></td><td>one PositionReportBunker object for each bunker category</td></tr><tr><td>Distance to next port</td><td><code>distanceToNextPort</code></td><td>Distance in nm to next port</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Draft Aft</td><td><code>draftAft</code></td><td>Vessel's draft aft</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Draft Forward</td><td><code>draftForward</code></td><td>Vessel's draft forward</td><td></td><td></td><td>Double</td><td></td></tr><tr><td>Fresh water ROB</td><td><code>robFw</code></td><td>Remaning fresh water on board</td><td></td><td></td><td>Double</td><td></td></tr></tbody></table>

### Departure Report example

<details>

<summary>Departure report on a port call</summary>

1. Assuming the voyage key, and port call sequence are known, get the PortCall key with this query:

```http
GET /ws/rest/PortCall?filter=voyage.key(EQ)123456&portCallSequence(EQ)2=null HTTP/1.1
Host: BASEURL
fields: {"eventLogs": {"event": {"eventCode":"*"}, "robs": {"bunkerCategory": {"bunkerCategoryCode":"*"}, "rob": "*"}}}
Authorization: Bearer ....
```

Example of the response can be found [here](#portcall-query-with-eventlogs-fields-response)

2. Generate a report that has fixes the departure date to  5th August 2024 08:30, departure FO rob at 225 mt and departure DL rob at 215 mt

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "DEP",
    "reportDateLocal": "2024-08-05T08:30:00",
    "portCall": 123456, //key from the response of the PortCall query
    "eventLogs": [
        {
            "key": 123456, //departure event log key
            "eventLogDate": "2024-08-05T08:30:00"
        }
    ],
    "positionReportBunkers": [
        {
            "bunkerCategory": 123456, //bunker category key
            "rob": 218.5
         
        },
        {
            "bunkerCategory": 654321, //bunker category key
            "rob": 225
        }
      ]
}
```

</details>

### More examples

<details>

<summary>PortCall query with "eventLogs" fields  response</summary>

```json
[
    {
        "key": 6130402,
        "eventLogs": [
            {
                "key": 6130391,
                "event": {
                    "key": 1000051,
                    "eventCode": "BRT"
                },
                "robs": [
                    {
                        "key": 6130447,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130450,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130462,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130464,
                        "rob": 249.75,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    }
                ]
            },
            {
                "key": 6130396,
                "event": {
                    "key": 6088041,
                    "eventCode": "UBRT"
                },
                "robs": [
                    {
                        "key": 6130444,
                        "rob": 249.75,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130452,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130459,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130470,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    }
                ]
            },
            {
                "key": 6130392,
                "event": {
                    "key": 1000052,
                    "eventCode": "DEP"
                },
                "robs": [
                    {
                        "key": 6130440,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130448,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130454,
                        "rob": 249.75,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130458,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    }
                ]
            },
            {
                "key": 6130395,
                "event": {
                    "key": 1000050,
                    "eventCode": "ARR"
                },
                "robs": [
                    {
                        "key": 6130451,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130460,
                        "rob": 250.0,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130467,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130469,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    }
                ]
            }
        ]
    },
    {
        "key": 6130400,
        "eventLogs": [
            {
                "key": 6130394,
                "event": {
                    "key": 1000051,
                    "eventCode": "BRT"
                },
                "robs": [
                    {
                        "key": 6130441,
                        "rob": 230.53559444257462,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130457,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130461,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130468,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    }
                ]
            },
            {
                "key": 6130398,
                "event": {
                    "key": 1000050,
                    "eventCode": "ARR"
                },
                "robs": [
                    {
                        "key": 6130445,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130456,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130463,
                        "rob": 230.78559444257462,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130471,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    }
                ]
            },
            {
                "key": 6130393,
                "event": {
                    "key": 6088041,
                    "eventCode": "UBRT"
                },
                "robs": [
                    {
                        "key": 6130442,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130443,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130453,
                        "rob": 230.53559444257462,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    },
                    {
                        "key": 6130466,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    }
                ]
            },
            {
                "key": 6130397,
                "event": {
                    "key": 1000052,
                    "eventCode": "DEP"
                },
                "robs": [
                    {
                        "key": 6130446,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916945,
                            "bunkerCategoryCode": "FL"
                        }
                    },
                    {
                        "key": 6130449,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916944,
                            "bunkerCategoryCode": "FO"
                        }
                    },
                    {
                        "key": 6130455,
                        "rob": 0.0,
                        "bunkerCategory": {
                            "key": 916946,
                            "bunkerCategoryCode": "DO"
                        }
                    },
                    {
                        "key": 6130465,
                        "rob": 230.53559444257462,
                        "bunkerCategory": {
                            "key": 916947,
                            "bunkerCategoryCode": "DL"
                        }
                    }
                ]
            }
        ]
    }
]
```

</details>

<details>

<summary>Arrival report with Remark</summary>

1. Send first this request

Example: Arrival vessel report to register arrival date at 8th August 2024 02:58, with remaining 98 MT of FO on board

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "ARR",
    "reportDateLocal": "2024-08-02T02:58:00",
    "portCall": 6130402, //key from the response of the PortCall request
    "eventLogs": [
        {
            "key": 6130395, //key of the arrival event log from the response of the PortCall request
            "eventLogDate": "2024-08-02T02:58:00"
        }],
      "positionReportBunkers": [
        {
            "bunkerCategory": "FO", 
            "rob": 98
        }]
}
```

2. The response of the query above returns the PositionReport key. Generate a Remark on the arrival position report that says "Arrival on the port remark":

```
POST /ws/rest/Remark HTTP/1.1
```

```
{
    source: 5535223, //key from the response of PositionReport request
    "remark": "Arrival on the port remark"
}
```

</details>

<details>

<summary>Arrival report where port call key and voyage key are not known, using voyage.referenceNo and port name</summary>

1. Fetch the port call key

{% code fullWidth="true" %}

```
GET /ws/rest/PortCall?filter=voyage.voyageHeader.referenceNo(LKIC)TST001&port.portName(LKIC)Bergen case insensitive HTTP/1.1
Authorization: Bearer ....
```

{% endcode %}

2. Generate arrival report

```http
POST /ws/rest/PositionReport HTTP/1.1
Host: BASEURL
Content-Type: application/json
Authorization: Bearer ....
```

```json
{
    "vesselReportType": "ARR",
    "reportDateLocal": "2024-08-02T02:58:00",
    "portCall": 6130402, //key from the response of the PortCall request
    "eventLogs": [
        {
            "key": 6130395, //key of the arrival event log from the response of the PortCall request
            "eventLogDate": "2024-08-02T02:58:00"
        }],
      "positionReportBunkers": [
        {
            "bunkerCategory": "FO", 
            "rob": 98
        }]
}
```

</details>


# Legacy version (6.26 - 6.28)

**Dataloy Vessel Report System** enables vessels to send vessel reports *without proper internet connection*. The server side of Dataloy VRS is exposed in the Dataloy API for inserting vessel reports into Dataloy VMS. When Dataloy VRS is in use, the client side of the Vessel Report API system can be ignored - the message sent by e-mail to the VRS is identical to what can be posted in the Vessel Report API (with minor adjustments). Inserting a vessel report into Dataloy VMS *not only* inserts a position report, but also the schedule, bunkers etc. There is also a functionality available for locating correct port call based on vessel code and report date.

Chapter Contents:&#x20;

* [Vessel Report API Process](#vessel-report-api-process)
* [Alerts](#alerts)
* [Noon report](#noon-report)
* [Arrival report](#arrival-report)
* [In Port Report](#in-port-report)
* [Departure Report](#departure-report)
* [Example Messages](#example-messages)
* [Consumption Breakdown](#consumption-breakdown)
* [Weather Data](#weather-data)
* [Direction](#direction)
* [Reason For Call](#direction)
* [Dataloy Vessel Code](#dataloy-vessel-code)
* [Dataloy Port ID](#dataloy-port-id)

### **Vessel Report API Process**

**Base URL**

The Vessel Report URL:

| `Base URL + ws/rest/VesselReport` |
| --------------------------------- |

**Custom Fields**

Custom fields can be added

* using Events (if there is an event code and date).
* or added as a Remark (text field).

Events are added and retrieved from [Master Data](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F6.46/master-data) and can be used in a JSON message. Event fields in the JSON message is shortened:

* ed = event date
* ec = event code.

Remarks will be connected to the Position Report. To send remarks requires:

* the set-up of a remark template in the database with a title and the extraction of the remark\_id.\
  ***Note**: This construction is usually met with various various challenges with e-mail based vessel reporting (more information:* [***contact Dataloy***](http://support.dataloy.com/)*).*

**IMPORTANT**: This type of construction causes various challenges with e-mail based vessel reporting (*more information: contact* [***contact Dataloy***](http://support.dataloy.com/)).

### **Alerts**

Alerts can be triggered either:

* when reports are inserted to Dataloy VMS
* or a report is failing.

**IMPORTANT**: Property Settings is handled in: *Master Data > Dataloy Properties*.

\
**Properties**

| Property                                                | Description                                                                                                                                                                                                                                                       |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| com.dataloy.integration.vessel.voyageNoAndRFC           | When set to **true**: referenceNo and reasonForCall can be added to the json message. This makes it easier for VRS to locate the correct port call and will reduce errors.                                                                                        |
| com.dataloy.integration.vessel.reportMailRecipients     | <p>List of email addresses separated by semicolon.</p><p>A vessel report successfully inserted into Dataloy VMS results in a report being sent to the addresses in this property value. The report will list all values sent from the vessel.</p>                 |
| com.dataloy.integration.vessel.errormail.recipient      | <ul><li>E-mail address list separated by semicolon.</li><li>The e-mail address owners will receive an e-mail if a vessel report is failing.</li><li>The Voyage Operator will also receive a message if the User has registered relevant e-mail address.</li></ul> |
| com.dataloy.integration.vessel.errormail.sender         | An e-mail address will be the sender of the Error Mail.                                                                                                                                                                                                           |
| com.dataloy.integration.vessel.sendReportMailToOperator | When set to true: A vessel report successfully inserted into Dataloy VMS results in a report being sent to the Voyage Operator, listing all values sent from the vessel.                                                                                          |
| com.dataloy.mail.smtp                                   | *smtp* must be setup for e-mail alerts to function.                                                                                                                                                                                                               |

### **Noon report**<br>

<table data-header-hidden><thead><tr><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>JSON Field Name</td><td>Description</td><td>Affects Dataloy VMS</td><td>Mandatory</td><td>Type</td><td>Length</td></tr><tr><td>portCallId</td><td>A port call id</td><td>If the port call id is available, use this to avoid VRS trying to locate the correct port call.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>referenceNo</td><td>Voyage reference number</td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>reasonForCall</td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>.</td><td><br></td><td><br></td><td><br></td></tr><tr><td><pre><code>reportTypeCode
</code></pre></td><td><ul><li>Vessel Report Type</li><li>Value = NOON for Noon Report</li></ul></td><td>Used to insert correct type of Position Report and to locate correct port call.</td><td>Yes</td><td>String</td><td>4</td></tr><tr><td><pre><code>vesselCode
</code></pre></td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Used in combination with report date local time to locate the port call in Dataloy VMS.</td><td>Yes</td><td>String</td><td>6</td></tr><tr><td><pre><code>reportDateLocal
</code></pre></td><td>Report Date Local Time</td><td>Used in combination with vessel code to locate the port call in Dataloy VMS. Inserted in the Postition Report.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>latitude
</code></pre></td><td>Position Latitude (Decimal Degrees)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td>5</td></tr><tr><td><pre><code>longitude
</code></pre></td><td>Position Longitude (Decimal Degress)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td>5</td></tr><tr><td><pre><code>portId
</code></pre></td><td>Arrival Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an error message will be returned and the report will not be inserted.</td><td>Yes</td><td>Integer</td><td>38</td></tr><tr><td><pre><code>arrival
</code></pre></td><td>Estimated Time of Arrival</td><td>Updates ETA in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>berthed
</code></pre></td><td>Estimated Time of Berthing</td><td>Updates ETB in Schedule.</td><td><br></td><td>Date</td><td><br></td></tr><tr><td><pre><code>departure
</code></pre></td><td>Estimated Time of Departure</td><td>Updates ETD in Schedule.</td><td><br></td><td>Date</td><td><br></td></tr><tr><td><pre><code>trueCourse
</code></pre></td><td>True Course</td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>distanceSailed
</code></pre></td><td>Distance Sailed Since Last Report</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>hoursInService
</code></pre></td><td>Hours in Service Since Last Report</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>distanceToNextPort
</code></pre></td><td>Distance To Go</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>speedMadeGood
</code></pre></td><td>Speed Made Good</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>windDirectionId
</code></pre></td><td>Wind Direction (<a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>)</td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>averageWindForce
</code></pre></td><td>Wind Force. Beaufort.</td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>seaDirectionId
</code></pre></td><td>Sea Direction (<a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>)<br></td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>averageSeaState
</code></pre></td><td>Sea State. Integer from 0 - 9.</td><td>Inserted in Position Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>bhpMainEngineIndicatedRpm
</code></pre></td><td>Main Engine RPM Since Last Report</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFo
</code></pre></td><td>Daily Fuel Oil Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyDo
</code></pre></td><td>Daily Diesel Oil Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFl
</code></pre></td><td>Daily Fuel Oil Low Sulphur Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyDl
</code></pre></td><td>Daily Diesel Oil Low Sulphur Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFw
</code></pre></td><td>Daily Net Fresh Water Consumption</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFo
</code></pre></td><td>Fuel Oil Remaining on Board (FO RoB)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDo
</code></pre></td><td>Diesel Oil Remaining on Board (DO RoB)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFl
</code></pre></td><td>Fuel Oil Low Sulphur Remaining on Board (FO LS RoB)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDl
</code></pre></td><td>Diesel Oil Low Sulphur Remaining on Board (DO LS RoB)</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFw
</code></pre></td><td>Fresh Water Remaining on Board</td><td>Inserted in Position Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>genericRemark
</code></pre></td><td>Remark</td><td>Inserted as a Remark to the Position Report.</td><td><br></td><td>String</td><td>Unlimited</td></tr></tbody></table>

### **Arrival report** <br>

<table data-header-hidden><thead><tr><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>JSON Field Name</td><td>Description</td><td>Affets Dataloy VMS</td><td>Mandatory</td><td>Type</td><td>Length</td></tr><tr><td>portCallId</td><td>A port call id</td><td>If the port call id is available, use this to avoid VRS trying to locate the correct port call.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>referenceNo</td><td>Voyage reference number</td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td>reasonForCall</td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>  </td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td><pre><code>reportTypeCode
</code></pre></td><td>Vessel Report Type<br>Value = ARR for Arrival Report.</td><td>Used to insert the correct type of Position Report and to locate the correct port call. </td><td>Yes</td><td>String</td><td>4</td></tr><tr><td><pre><code>vesselCode
</code></pre></td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Used in combination with report date local time to locate the port call in Dataloy VMS.</td><td>Yes</td><td>String</td><td>6</td></tr><tr><td><pre><code>portId
</code></pre></td><td>Arrival Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an error message will be returned and the report will not be inserted.</td><td>Yes</td><td>Integer</td><td>38</td></tr><tr><td><pre><code>reportDateLocal
</code></pre></td><td>Report Date Local Time</td><td>Used in combination with vessel code to locate the port call in Dataloy VMS.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>arrival
</code></pre></td><td>Time of Arrival</td><td>Updates ETA in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>berthed
</code></pre></td><td>Time of Berthing (Estimated if Anchoring)</td><td>Updates ETB in Schedule</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>departure
</code></pre></td><td>Estimated Time of Departure</td><td>Updates ETD in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>distanceSailedSinceDeparture
</code></pre></td><td>Total Distance Sailed Since Departure</td><td>Updates Miles in Schedule.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>distanceSailed
</code></pre></td><td>Distance Sailed Since Last Report</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>hoursStoppages
</code></pre></td><td>Hours Stoppages</td><td>Updates Days Stoppages (<em>see the Perfomance tab in Booking and Operations</em>).</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>hoursInService
</code></pre></td><td>Hours in Service</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>speedMadeGood
</code></pre></td><td>Speed Made Good Since Last Report</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>draftAft
</code></pre></td><td>Draft Aft</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>draftForward
</code></pre></td><td>Draft Forward</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFo
</code></pre></td><td>Daily Fuel Oil Consumption<br></td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyDo
</code></pre></td><td>Daily Diesel Oil Consumption</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFl
</code></pre></td><td>Daily Fuel Oil Low Sulphur Consumption</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyDl
</code></pre></td><td>Daily Diesel Oil Low Sulphur Consumption</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dailyFw
</code></pre></td><td>Daily Net Fresh Water consumption</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFo
</code></pre></td><td>Fuel Oil Remaining on Board (FO RoB)</td><td>Updates Fuel Oil Remaining on Board (FO RoB) Arrival.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDo
</code></pre></td><td>Diesel Oil Remaining on Board (DO RoB)</td><td>Updates Diesel Oil Remaining on Board (DO RoB) Arrival.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFl
</code></pre></td><td>Fuel Oil Low Sulphur Remaining on Board (FO LS RoB)</td><td>Updates Fuel Oil Low Sulphur Remaining on Board (FO LS RoB) Arrival.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDl
</code></pre></td><td>Diesel Oil Low Sulphur Remaining on Board (DO LS RoB)</td><td>Updates Diesel Oil Low Sulphur Remaining on Board (DO LS RoB) Arrival.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFw
</code></pre></td><td>Fresh Water remaining on board</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>genericRemark
</code></pre></td><td>Remark</td><td>Inserted as a Remark to the Position Report.</td><td><br></td><td>String</td><td>Unlimited</td></tr></tbody></table>

### **In Port Report**<br>

<table data-header-hidden><thead><tr><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>JSON Field Name</td><td>Description</td><td>Affects Dataloy VMS</td><td>Mandatory</td><td>Type</td><td>Length</td></tr><tr><td>portCallId</td><td>A port call id</td><td>If the port call id is available, use this to avoid VRS trying to locate the correct port call.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>referenceNo</td><td>Voyage reference number</td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td>reasonForCall</td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>  </td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td><pre><code>reportTypeCode
</code></pre></td><td>Vessel Report Type<br>Value = PORT for In Port Report.</td><td>Used to insert the correct type of Position Report and to locate the correct port call.</td><td>Yes</td><td>String</td><td>4</td></tr><tr><td><pre><code>vesselCode
</code></pre></td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Used in combination with report date local time to locate the port call in Dataloy VMS.</td><td>Yes</td><td>String</td><td>6</td></tr><tr><td><pre><code>portId
</code></pre></td><td>Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an error message will be returned and the report will not be inserted.</td><td>Yes</td><td>Integer</td><td>38</td></tr><tr><td><pre><code>reportDateLocal
</code></pre></td><td>Report Date Local Time</td><td>Used in combination with vessel code to locate the port call in Dataloy.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>berthed
</code></pre></td><td>Estimated Time of Berthing</td><td>Updates ETB in Schedule</td><td><br></td><td>Date</td><td><br></td></tr><tr><td><pre><code>departure
</code></pre></td><td>Estimated Time of Departure</td><td>Updates ETD in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>hoursInService
</code></pre></td><td>Hours in Service</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>weatherId
</code></pre></td><td>Weather. <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Inserted in Postion Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>windDirectionId
</code></pre></td><td>Wind Direction. <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a> </td><td>Inserted in Postion Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>averageWindForce
</code></pre></td><td>Average Wind Force. Beaufort.</td><td>Inserted in Postion Report.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>genericRemark
</code></pre></td><td>Remark</td><td>Inserted as a Remark to the Position Report.</td><td><br></td><td>String</td><td>Unlimited</td></tr></tbody></table>

### &#x20;**Departure Report**<br>

<table data-header-hidden><thead><tr><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>JSON Field Name</td><td>Description</td><td>Affects Dataloy VMS</td><td>Mandatory</td><td>Type</td><td>Length</td></tr><tr><td>portCallId</td><td>A port call id</td><td>If the port call id is available, use this to avoid VRS trying to locate the correct port call.</td><td><br></td><td><br></td><td><br></td></tr><tr><td>referenceNo</td><td>Voyage reference number</td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td>reasonForCall</td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>  </td><td>Makes it easier for VRS to locate correct port call which results in less errors. Requires a <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a>. </td><td><br></td><td><br></td><td><br></td></tr><tr><td><pre><code>reportTypeCode
</code></pre></td><td>Vessel Report Type.<br>Value = DEP for Departure Report.</td><td>Used to insert the correct type of position report and to locate the correct port call.</td><td>Yes</td><td>String</td><td>4</td></tr><tr><td><pre><code>vesselCode
</code></pre></td><td><a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>Used in combination with report date local time to locate the port call in Dataloy VMS.</td><td>Yes</td><td>String</td><td>6</td></tr><tr><td><pre><code>portId
</code></pre></td><td>Departure Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an error message will be returned and the report will not be inserted.</td><td>Yes</td><td>Integer</td><td>38</td></tr><tr><td><pre><code>reportDateLocal
</code></pre></td><td>Report Date Local Time</td><td>Used in combination with vessel code to locate the port call in Dataloy VMS.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>departure
</code></pre></td><td>Departure Time</td><td>Updates Estimated Time of Departure (ETD) in Schedule.</td><td>Yes</td><td>Date</td><td><br></td></tr><tr><td><pre><code>nextPortId
</code></pre></td><td>Next Arrival Port, <a href="https://dataloy-cloud.atlassian.net/wiki/pages/viewpage.action?pageId=3112173569&#x26;pageVersion=1#">924581992</a></td><td>When a port call is located based on vessel and report date, Dataloy VMS checks the reported port against the port in Dataloy VMS.<br>If these do not match an e-mail will be sent to the operator and the report will not be inserted.</td><td><br></td><td>Integer</td><td>38</td></tr><tr><td><pre><code>arrival
</code></pre></td><td>Estimated Time of Arrival</td><td>Updates Estimate Time of Arrival (ETA) for next Arrival Port.</td><td><br></td><td>Date</td><td><br></td></tr><tr><td><pre><code>distanceToNextPort
</code></pre></td><td>Distance To Next Port</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>draftAft
</code></pre></td><td>Draft Aft</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>draftForward
</code></pre></td><td>Draft Forward</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFo
</code></pre></td><td>Fuel Oil Remaining on Board (FO RoB)</td><td>Updates Fuel Oil Remaining on Board (FO RoB) departure.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDo
</code></pre></td><td>Diesel Oil Remaining on Board (DO RoB)</td><td>Updates Diesel Oil Remaining on Board (DO RoB) departure.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFl
</code></pre></td><td>Fuel Oil Low Sulphur Remaining on Board (FO LS RoB)</td><td>Updates Fuel Oil Low Sulphur Remaining on Board (FO LS RoB) departure.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robDl
</code></pre></td><td>Diesel Oil Low Sulphur Remaining on Board (DO LS RoB)</td><td>Updates Diesel Oil Low Sulphur Remaining on Board (FO LS RoB) departure.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>robFw
</code></pre></td><td>Fresh Water Remaining on Board</td><td>Inserted in Postion Report.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>foBunkered
</code></pre></td><td>Bunkered Fuel Oil<br>Input Exact Figure According to BDR</td><td>Updates Fuel Oil bunkered for departure port call.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>flBunkered
</code></pre></td><td>Bunkered Fuel Oil Low Sulphur<br>Input exact figure according to the BDR</td><td>Updates Fuel Oil Low Sulphur bunkered for departure port call.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>doBunkered
</code></pre></td><td>Bunkered Diesel Oil<br>Input exact figure according to the BDR</td><td>Updates Diesel Oil bunkered for departure port call.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>dlBunkered
</code></pre></td><td>Bunkered Diesel Oil Low Sulphur<br>Input exact figure according to the BDR</td><td>Updates Diesel Oil Low Sulphur bunkered for departure port call.</td><td><br></td><td>Double</td><td><br></td></tr><tr><td><pre><code>genericRemark
</code></pre></td><td>Remark</td><td>Inserted as remark to position report.</td><td><br></td><td>String</td><td>Unlimited</td></tr></tbody></table>

### &#x20;**Example Messages**

Updated for [API version 2.0.0](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404316/Dataloy+API+2.0+Release+Notes) using the new required date format **yyyy-dd-MMThh:mi:ss** to conform ISO 8601, (prior version has date format: yyyy-dd-MM hh:mi:ss)

Arrival

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><p></p><pre class="language-postman_json"><code class="lang-postman_json">{
    "remarks": [],
    "events": [
        {
            "ed": "2013-12-24T00:00:00",
            "ec": "VR05"
        },
        {
            "ed": "2013-12-24T00:00:00",
            "ec": "VR10"
        }
    ],
    "reportTypeCode": "ARR",
    "vesselCode": "14",
    "portId": "104419",
    "reportDateLocal": "2013-12-24T00:00:00",
    "arrival": "2013-12-24T00:00:00",
    "berthed": "2013-12-24T00:00:00",
    "departure": "2013-12-24T00:00:00",
    "distanceSailed": "10",
    "distanceSailedSinceDeparture": "10",
    "hoursInService": "10",
    "hoursStoppages": "10",
    "speedMadeGood": "10",
    "draftAft": "10",
    "draftForward": "10",
    "dailyFo": "10",
    "dailyDo": "10",
    "dailyFl": "10",
    "dailyDl": "10",
    "dailyFw": "10",
    "robFo": "10",
    "robDo": "10",
    "robFl": "10",
    "robDl": "10",
    "robFw": "10",
    "genericRemark": "Remark"
}
</code></pre></td></tr></tbody></table>

Departure

| `{    "remarks":[        {            "id":"70495513",            "r":"10"        },        {            "id":"70495512",            "r":"10"        },        {            "id":"70495511",            "r":"10"        },        {            "id":"70495510",            "r":"10"        },        {            "id":"70495509",            "r":"10"        },        {            "id":"70495514",            "r":"10"        },        {            "id":"70495515",            "r":"10"        },        {            "id":"70495516",            "r":"10"        },        {            "id":"70495517",            "r":"10"        },        {            "id":"70495518",            "r":"10"        },        {            "id":"70495519",            "r":"10"        }    ],    "events":[        {            "ed":"2013-12-24T00:00:00",            "ec":"VR15"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR20"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR25"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR30"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR40"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR45"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR50"        },        {            "ed":"2013-12-24T00:00:00",            "ec":"VR55"        }    ],    "reportTypeCode":"DEP",    "vesselCode":"14",    "portId":"104419",    "reportDateLocal":"2013-12-24T00:00:00",    "departure":"2013-12-24T00:00:00",    "nextPortId":"104419",    "arrival":"2013-12-24T00:00:00",    "distanceToNextPort":"10",    "draftAft":"10",    "draftForward":"10",    "robFo":"10",    "robDo":"10",    "robFl":"10",    "robDl":"10",    "robFw":"10",    "foBunkered":"10",    "flBunkered":"10",    "doBunkered":"10",    "dlBunkered":"10",    "genericRemark":"Remark"}` |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

Noon

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><p></p><pre class="language-postman_json"><code class="lang-postman_json">{
    "events": [],
    "reportTypeCode": "NOON",
    "vesselCode": "14",
    "latitude": 10.17,
    "longitude": 10.17,
    "portId": "104419",
    "reportDateLocal": "2013-12-24T00:00:00",
    "arrival": "2013-12-24T00:00:00",
    "berthed": "2013-12-24T00:00:00",
    "departure": "2013-12-24T00:00:00",
    "trueCourse": "10",
    "distanceSailed": "10",
    "hoursInService": "10",
    "distanceToNextPort": "10",
    "speedMadeGood": "10",
    "windDirectionId": "911638",
    "averageWindForce": "0",
    "seaDirectionId": "911638",
    "averageSeaState": "1",
    "bhpMainEngineIndicatedRpm": "10",
    "dailyFo": "10",
    "dailyDo": "10",
    "dailyFl": "10",
    "dailyDl": "10",
    "dailyFw": "10",
    "robFo": "10",
    "robDo": "10",
    "robFl": "10",
    "robDl": "10",
    "robFw": "10",
    "genericRemark": "Remark"
}
</code></pre></td></tr></tbody></table>

Port

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><p></p><pre class="language-postman_json"><code class="lang-postman_json">{
    "remarks": [
        {
            "id": "70495526",
            "r": "100"
        },
        {
            "id": "70495527",
            "r": "100"
        },
        {
            "id": "70495528",
            "r": "100"
        }
    ],
    "events": [
        {
            "ed": "2013-12-24T00:00:00",
            "ec": "VR60"
        }
    ],
    "reportTypeCode": "PORT",
    "vesselCode": "14",
    "portId": "104419",
    "reportDateLocal": "2013-12-24T00:00:00",
    "berthed": "2013-12-24T00:00:00",
    "departure": "2013-12-24T00:00:00",
    "hoursInService": "20",
    "weatherId": "950936",
    "windDirectionId": "913903",
    "averageWindForce": "1",
    "genericRemark": "Remark"
}
</code></pre></td></tr></tbody></table>

<br>

### **Consumption Breakdown**

The following fields can be added for consumption breakdown

| Main Engine - Fuel Oil                                                | Inserted to position report. |
| --------------------------------------------------------------------- | ---------------------------- |
| Main Engine - Fuel Oil Low Sulphur                                    | Inserted to position report. |
| Main Engine - Diesel Oil                                              | Inserted to position report. |
| Main Engine - Diesel Oil Low Sulphur                                  | Inserted to position report. |
| Auxiliary - Fuel Oil At Sea                                           | Inserted to position report. |
| Auxiliary - Fuel Oil Low Sulphur At Sea                               | Inserted to position report. |
| Auxiliary - Diesel Oil At Sea                                         | Inserted to position report. |
| Auxiliary - Diesel Oil Low Sulphur At SeaInserted to position report. | Inserted to position report. |
| Boilers - Fuel Oil Idle                                               | Inserted to position report. |
| Boilers - Fuel Oil Low Sulphur Idle                                   | Inserted to position report. |
| Boilers - Diesel Oil Idle                                             | Inserted to position report. |
| Boilers - Diesel Oil Low Sulphur Idle                                 | Inserted to position report. |
| Boilers - Fuel Oil Working                                            | Inserted to position report. |
| Boilers - Fuel Oil Low Sulphur Working                                | Inserted to position report. |
| Boilers - Diesel Oil Working                                          | Inserted to position report. |
| Boilers - Diesel Oil Low Sulphur Working                              | Inserted to position report. |
| Generators - Fuel Oil At Sea                                          | Inserted to position report. |
| Generators - Fuel Oil Low Sulphur At Sea                              | Inserted to position report. |
| Generators - Diesel Oil At Sea                                        | Inserted to position report. |
| Generators - Diesel Oil Low Sulphur At Sea                            | Inserted to position report. |
| Cleaning - Fuel Oil                                                   | Inserted to position report. |
| Cleaning - Fuel Oil Low Sulphur                                       | Inserted to position report. |
| Cleaning - Diesel Oil                                                 | Inserted to position report. |
| Cleaning - Diesel Oil Low Sulphur                                     | Inserted to position report. |
| Heating - Fuel Oil Consumption                                        | Inserted to position report. |
| Heating - Fuel Oil Low Sulphur                                        | Inserted to position report. |
| Heating - Diesel Oil                                                  | Inserted to position report. |
| Heating - Diesel Oil Low Sulphur                                      | Inserted to position report. |

<br>

### **Weather Data**

When inserting weather data, use the ID from the Weather Data table:

<table data-header-hidden><thead><tr><th width="411"></th><th></th></tr></thead><tbody><tr><td>Weather ID</td><td>Weather Description</td></tr><tr><td><pre><code>950926
</code></pre></td><td>Clear Sky</td></tr><tr><td><pre><code>950927
</code></pre></td><td>Sunny Day</td></tr><tr><td><pre><code>950928
</code></pre></td><td>Partly Cloudy</td></tr><tr><td><pre><code>950929
</code></pre></td><td>Sunny Intervals</td></tr><tr><td><pre><code>950930
</code></pre></td><td>Dust</td></tr><tr><td><pre><code>950931
</code></pre></td><td>Mist</td></tr><tr><td><pre><code>950932
</code></pre></td><td>Fog</td></tr><tr><td><pre><code>950933
</code></pre></td><td>Medium-Level Cloud</td></tr><tr><td><pre><code>950934
</code></pre></td><td>Low-Level Cloud</td></tr><tr><td><pre><code>950935
</code></pre></td><td>Light Rain Shower</td></tr><tr><td><pre><code>950936
</code></pre></td><td>Drizzle</td></tr><tr><td><pre><code>950937
</code></pre></td><td>Light Rain</td></tr><tr><td><pre><code>950938
</code></pre></td><td>Heavy Rain Shower</td></tr><tr><td><pre><code>950939
</code></pre></td><td>Heavy Rain</td></tr><tr><td><pre><code>950940
</code></pre></td><td>Sleet Shower</td></tr><tr><td><pre><code>950941
</code></pre></td><td>Sleet</td></tr><tr><td><pre><code>950942
</code></pre></td><td>Hail Shower</td></tr><tr><td><pre><code>950943
</code></pre></td><td>Hail</td></tr><tr><td><pre><code>950944
</code></pre></td><td>Light Snow Shower</td></tr><tr><td><pre><code>950945
</code></pre></td><td>Light Snow</td></tr><tr><td><pre><code>950946
</code></pre></td><td>Heavy Snow Shower</td></tr><tr><td><pre><code>950947
</code></pre></td><td>Heavy Snow</td></tr><tr><td><pre><code>950948
</code></pre></td><td>Thundery Shower</td></tr><tr><td><pre><code>950949
</code></pre></td><td>Thunder Storm</td></tr><tr><td><pre><code>950950
</code></pre></td><td>Tropical Storm</td></tr><tr><td><pre><code>950951
</code></pre></td><td>Haze</td></tr></tbody></table>

### **Direction**

When inserting direction, use the ID from the Direction Table:

<table data-header-hidden><thead><tr><th></th><th></th></tr></thead><tbody><tr><td>Direction id</td><td>Direction Description</td></tr><tr><td><pre><code>911636
</code></pre></td><td>North</td></tr><tr><td><pre><code>911637
</code></pre></td><td>South</td></tr><tr><td><pre><code>911638
</code></pre></td><td>East</td></tr><tr><td><pre><code>911639
</code></pre></td><td>West</td></tr><tr><td><pre><code>911640
</code></pre></td><td>North/East</td></tr><tr><td><pre><code>911641
</code></pre></td><td>North/West</td></tr><tr><td><pre><code>911642
</code></pre></td><td>South/East</td></tr><tr><td><pre><code>911643
</code></pre></td><td>South/West</td></tr><tr><td><pre><code>913753
</code></pre></td><td>Various</td></tr><tr><td><pre><code>913902
</code></pre></td><td>North/North/East</td></tr><tr><td><pre><code>913903
</code></pre></td><td>East/North/East</td></tr><tr><td><pre><code>913904
</code></pre></td><td>East/South/East</td></tr><tr><td><pre><code>913905
</code></pre></td><td>South/South/East</td></tr><tr><td><pre><code>913906
</code></pre></td><td>South/South/West</td></tr><tr><td><pre><code>913907
</code></pre></td><td>West/South/West</td></tr><tr><td><pre><code>913908
</code></pre></td><td>West/North/West</td></tr><tr><td><pre><code>913909
</code></pre></td><td>North/North/West</td></tr><tr><td><pre><code>916765
</code></pre></td><td>East/by/North</td></tr><tr><td><pre><code>916766
</code></pre></td><td>East/by/South</td></tr><tr><td><pre><code>916767
</code></pre></td><td>North/by/East</td></tr><tr><td><pre><code>916768
</code></pre></td><td>North/by/West</td></tr><tr><td><pre><code>916769
</code></pre></td><td>NE/by/East</td></tr><tr><td><pre><code>916770
</code></pre></td><td>NE/by/north</td></tr><tr><td><pre><code>916771
</code></pre></td><td>NW/by/North</td></tr><tr><td><pre><code>916772
</code></pre></td><td>NW/by/West</td></tr><tr><td><pre><code>916773
</code></pre></td><td>SE/by/East</td></tr><tr><td><pre><code>916774
</code></pre></td><td>SE/by/South</td></tr><tr><td><pre><code>916775
</code></pre></td><td>SW/by/South</td></tr><tr><td><pre><code>916776
</code></pre></td><td>SW/by/West</td></tr><tr><td><pre><code>916777
</code></pre></td><td>South/by/East</td></tr><tr><td><pre><code>916778
</code></pre></td><td>South/by/West</td></tr><tr><td><pre><code>916779
</code></pre></td><td>West/by/North</td></tr><tr><td><pre><code>916780
</code></pre></td><td>West/by/South</td></tr></tbody></table>

### **Reason For Call**

| Code | Description          |
| ---- | -------------------- |
| L    | Loading              |
| D    | Discharging          |
| C    | Canal Passage        |
| E    | Extra Port           |
| DD   | Dry Dock             |
| DEL  | Delivery             |
| RED  | Redelivery           |
| B    | Bunkering            |
| R    | Repair               |
| CL   | Tank / Hold Cleaning |
| STS  | Ship to Ship         |
| W    | Waiting              |
| CC   | Customs Clearance    |

<br>

<br>

### **Dataloy Vessel Code**

Dataloy Vessel Codes can be found by using the [Vessel Code Resource](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F6.46/model/schemas/vessel-code).

### **Dataloy Port ID**

Dataloy Port ID's can be found be using the [Port Resource](https://dataloy-systems.stoplight.io/docs/dataloyModel/branches/API%2F6.46/model/schemas/port).


# Vessel report master data

### Direction data

<table data-header-hidden><thead><tr><th></th><th></th></tr></thead><tbody><tr><td>Direction id</td><td>Direction Description</td></tr><tr><td><pre><code>911636
</code></pre></td><td>North</td></tr><tr><td><pre><code>911637
</code></pre></td><td>South</td></tr><tr><td><pre><code>911638
</code></pre></td><td>East</td></tr><tr><td><pre><code>911639
</code></pre></td><td>West</td></tr><tr><td><pre><code>911640
</code></pre></td><td>North/East</td></tr><tr><td><pre><code>911641
</code></pre></td><td>North/West</td></tr><tr><td><pre><code>911642
</code></pre></td><td>South/East</td></tr><tr><td><pre><code>911643
</code></pre></td><td>South/West</td></tr><tr><td><pre><code>913753
</code></pre></td><td>Various</td></tr><tr><td><pre><code>913902
</code></pre></td><td>North/North/East</td></tr><tr><td><pre><code>913903
</code></pre></td><td>East/North/East</td></tr><tr><td><pre><code>913904
</code></pre></td><td>East/South/East</td></tr><tr><td><pre><code>913905
</code></pre></td><td>South/South/East</td></tr><tr><td><pre><code>913906
</code></pre></td><td>South/South/West</td></tr><tr><td><pre><code>913907
</code></pre></td><td>West/South/West</td></tr><tr><td><pre><code>913908
</code></pre></td><td>West/North/West</td></tr><tr><td><pre><code>913909
</code></pre></td><td>North/North/West</td></tr><tr><td><pre><code>916765
</code></pre></td><td>East/by/North</td></tr><tr><td><pre><code>916766
</code></pre></td><td>East/by/South</td></tr><tr><td><pre><code>916767
</code></pre></td><td>North/by/East</td></tr><tr><td><pre><code>916768
</code></pre></td><td>North/by/West</td></tr><tr><td><pre><code>916769
</code></pre></td><td>NE/by/East</td></tr><tr><td><pre><code>916770
</code></pre></td><td>NE/by/north</td></tr><tr><td><pre><code>916771
</code></pre></td><td>NW/by/North</td></tr><tr><td><pre><code>916772
</code></pre></td><td>NW/by/West</td></tr><tr><td><pre><code>916773
</code></pre></td><td>SE/by/East</td></tr><tr><td><pre><code>916774
</code></pre></td><td>SE/by/South</td></tr><tr><td><pre><code>916775
</code></pre></td><td>SW/by/South</td></tr><tr><td><pre><code>916776
</code></pre></td><td>SW/by/West</td></tr><tr><td><pre><code>916777
</code></pre></td><td>South/by/East</td></tr><tr><td><pre><code>916778
</code></pre></td><td>South/by/West</td></tr><tr><td><pre><code>916779
</code></pre></td><td>West/by/North</td></tr><tr><td><pre><code>916780
</code></pre></td><td>West/by/South</td></tr></tbody></table>

### Weather data

<table data-header-hidden><thead><tr><th width="411"></th><th></th></tr></thead><tbody><tr><td>Weather ID</td><td>Weather Description</td></tr><tr><td><pre><code>950926
</code></pre></td><td>Clear Sky</td></tr><tr><td><pre><code>950927
</code></pre></td><td>Sunny Day</td></tr><tr><td><pre><code>950928
</code></pre></td><td>Partly Cloudy</td></tr><tr><td><pre><code>950929
</code></pre></td><td>Sunny Intervals</td></tr><tr><td><pre><code>950930
</code></pre></td><td>Dust</td></tr><tr><td><pre><code>950931
</code></pre></td><td>Mist</td></tr><tr><td><pre><code>950932
</code></pre></td><td>Fog</td></tr><tr><td><pre><code>950933
</code></pre></td><td>Medium-Level Cloud</td></tr><tr><td><pre><code>950934
</code></pre></td><td>Low-Level Cloud</td></tr><tr><td><pre><code>950935
</code></pre></td><td>Light Rain Shower</td></tr><tr><td><pre><code>950936
</code></pre></td><td>Drizzle</td></tr><tr><td><pre><code>950937
</code></pre></td><td>Light Rain</td></tr><tr><td><pre><code>950938
</code></pre></td><td>Heavy Rain Shower</td></tr><tr><td><pre><code>950939
</code></pre></td><td>Heavy Rain</td></tr><tr><td><pre><code>950940
</code></pre></td><td>Sleet Shower</td></tr><tr><td><pre><code>950941
</code></pre></td><td>Sleet</td></tr><tr><td><pre><code>950942
</code></pre></td><td>Hail Shower</td></tr><tr><td><pre><code>950943
</code></pre></td><td>Hail</td></tr><tr><td><pre><code>950944
</code></pre></td><td>Light Snow Shower</td></tr><tr><td><pre><code>950945
</code></pre></td><td>Light Snow</td></tr><tr><td><pre><code>950946
</code></pre></td><td>Heavy Snow Shower</td></tr><tr><td><pre><code>950947
</code></pre></td><td>Heavy Snow</td></tr><tr><td><pre><code>950948
</code></pre></td><td>Thundery Shower</td></tr><tr><td><pre><code>950949
</code></pre></td><td>Thunder Storm</td></tr><tr><td><pre><code>950950
</code></pre></td><td>Tropical Storm</td></tr><tr><td><pre><code>950951
</code></pre></td><td>Haze</td></tr></tbody></table>


# Bunker Consumption API

### Consumption and bunker related figures for a given voyage are stored in VoyageBunker and Rob resources

### VoyageBunker - Bunker summary of entire voyage

Each voyage is linked to one VoyageBunker object for each bunker category that is used during the voyage. VoyageBunker stores the following information/fields:

* **bunkerCategory**: the BunkerCategory connected to the VoyageBunker object
* **consumption**: total consumption of the bunker during the voyage
* **cost**: total bunker cost during the voyage
* **price**:  average bunker price during the voyage
* **priceVoyageStart**: average bunker price at voyage start
* **priceVoyageEnd**: average bunker price at voyage end
* **profitLoss**: the charterer's total bunker profit/loss
* **profitLossTcIn**: the owner's total bunker profit/loss
* **robDelivery**: bunker ROB at delivery port
* **robRedelivery**: bunker ROB at redelivery port
* **robVoyageStart**: bunker ROB at voyage start
* **voyage**: the Voyage connected to the VoyageBunker

The following request fetches all VoyageBunker objects for a given voyage:\
\
`https://BASE_URL/ws/rest/VoyageBunker?filter=voyage.key(EQ)20012412`

Alternatively, a request can be sent against /Voyage/20012412 with *voyageBunkers* defined in the header fields. The JSON below is an example response of above requests. Two different bunkers are used during this voyage, *FO* and *LS MGO*.

```json
[
    {
        "key": 20027578,
        "self": "https://BASE_URL/ws/rest/VoyageBunker/20027578",
        "bunkerCategory": {
            "key": 13575292,
            "self": "https://BASE_URL/ws/rest/BunkerCategory/13575292",
            "bunkerCategoryName": "FO",
        },
        "consumption": 530.0,
        "cost": 359340.0,
        "price": 678.0,
        "priceVoyageStart": 678.0,
        "priceVoyageEnd": 678.0,
        "profitLoss": 0.0,
        "profitLossTcIn": 0.0,
        "robDelivery": 0.0,
        "robRedelivery": 0.0,
        "robVoyageStart": 600.0,
        "voyage": {
            "key": 20012412,
            "self": "https://BASE_URL/ws/rest/Voyage/20012412",
        }
    },
    {
        "key": 20027579,
        "self": "https://BASE_URL/ws/rest/VoyageBunker/20027579",
        "bunkerCategory": {
            "key": 13575293,
            "self": "https://BASE_URL/ws/rest/BunkerCategory/13575293",
            "bunkerCategoryName": "LS MGO",
        },
        "consumption": 120.0,
        "cost": 93240.0,
        "price": 777.0,
        "priceVoyageStart": 777.0,
        "priceVoyageEnd": 777.0,
        "profitLoss": 0.0,
        "profitLossTcIn": 0.0,
        "robDelivery": 0.0,
        "robRedelivery": 0.0,
        "robVoyageStart": 200.0,
        "voyage": {
            "key": 20012412,
            "self": "https://BASE_URL/ws/rest/Voyage/20012412",
        }
    }
]
```

### Rob - Bunkers per leg&#x20;

*Rob = remaining on board.*\
\
Rob objects stores bunker related numbers for a single leg on the Voyage. A Rob is connected to a PortCall through EventLogs. Each EventLog contains an underlying Event with an eventCode attribute, and there are four eventCodes relevant for Robs - 'ARR', 'BRT', 'UBRT', and 'DEP', corresponding to Arrival, Berth, Unberth, and Departure, respectively.&#x20;

As an example, the following request can be used to fetch all Robs for a given EventLog:

`https://BASE_URL/ws/rest/EventLog/20027578`

Assuming this EventLog is linked to the *arrival* event, the returned Robs contains at-sea consumption from previous port call, and fuel remaining upon arrival (for each bunker). Below is an example JSON response:

```json
{
    "key": 20027578,
    "self": "https://BASE_URL/ws/rest/EventLog/20027578",
    "event": {
        "key": 13575292,
        "self": "https://BASE_URL/ws/rest/Event/13575292",
        "eventCode": "UBRT"
    },
    "robs": [
        {
            "key": 20027642,
            "self": "https://BASE_URL/ws/rest/Rob/20027642",
            "bunkerCategory": {
                "key": 916944,
                "self": "https://BASE_URL/ws/rest/BunkerCategory/916944",
                "bunkerCategoryCode": "FO"
            },
            "robFixed": false,
            "rob": 0.0,
            "consumption": 0.0
        },
        {
            "key": 20027649,
            "self": "https://BASE_URL/ws/rest/Rob/20027649",
            "bunkerCategory": {
                "key": 916947,
                "self": "https://BASE_URL/ws/rest/BunkerCategory/916947",
                "bunkerCategoryCode": "DL"
            },
            "robFixed": false,
            "rob": -4.61125655636663,
            "consumption": 0.0
        },
        {
            "key": 20027651,
            "self": "https://BASE_URL/ws/rest/Rob/20027651",
            "bunkerCategory": {
                "key": 916945,
                "self": "https://BASE_URL/ws/rest/BunkerCategory/916945",
                "bunkerCategoryCode": "FL"
            },
            "robFixed": false,
            "rob": 0.0,
            "consumption": 0.0
        },
        {
            "key": 20027663,
            "self": "https://BASE_URL/ws/rest/Rob/20027663",
            "bunkerCategory": {
                "key": 916946,
                "self": "https://BASE_URL/ws/rest/BunkerCategory/916946",
                "bunkerCategoryCode": "DO"
            },
            "robFixed": false,
            "rob": 0.0,
            "consumption": 0.0
        }
    ]
}
```

*Note! To get the same response, the following header fields must be specified:* `{"event":{"eventCode":"*"},"robs": {"`*`consumption":"*"`*`,"robFixed":"*"`*`,"rob": "*"`*`,"bunkerCategory":{"bunkerCategoryCode":"*"}}}`

To retrieve a list of Robs for a given EventLog, use the "robs" field. The number of Robs returned corresponds to the number of BunkerCategories in the system.

### Rob fields

```
{
  "eventLog": {},
  "robFixed": true,
  "bunkerCategory": {},
  "rob": -1.7976931348623157e+308,
  "consumption": -1.7976931348623157e+308
}
```

Attributes breakdown:

* bunkerCategory - the BunkerCategory connected to the Rob
* eventLog - the EventLog connected to the Rob
* rob - remaining fuel onboard
* consumption - the bunker consumption between previous event and the connected event
* robFixed - identifies whether the rob value is fixed or not

### How do we get the total consumption for a Port Call?

To get total consumption for a Port Call, Robs for all EventLogs on the PortCalls must be acquired.

The list of all EventLogs can be referenced directly from a PortCall:

Header fields: `{"eventLogs": {"event":{"eventCode":"*"},"robs": {"`*`consumption":"*"`*`,"robFixed":"*"`*`,"rob": "*"`*`,"bunkerCategory":{"bunkerCategoryCode":"*"}}}}`

Response:

```
{
    "key": 20027590,
    "self": "https://BASE_URL/ws/rest/PortCall/20027590",
    "eventLogs": [
        {
            "key": 20027578,
            "self": "https://BASE_URL/ws/rest/EventLog/20027578",
            "event": {
                "key": 13575292,
                "self": "https://BASE_URL/ws/rest/Event/13575292",
                "eventCode": "UBRT"
            },
            "robs": [
                {
                    "key": 20027642,
                    "self": "https://BASE_URL/ws/rest/Rob/20027642",
                    "bunkerCategory": {
                        "key": 916944,
                        "self": "https://BASE_URL/ws/rest/BunkerCategory/916944",
                        "bunkerCategoryCode": "FO"
                    },
                    "robFixed": false,
                    "rob": 0.0,
                    "consumption": 0.0
                },
                {
                    "key": 20027649,
                    "self": "https://BASE_URL/ws/rest/Rob/20027649",
                    "bunkerCategory": {
                        "key": 916947,
                        "self": "https://BASE_URL/ws/rest/BunkerCategory/916947",
                        "bunkerCategoryCode": "DL"
                    },
                    "robFixed": false,
                    "rob": -4.61125655636663,
                    "consumption": 0.0
                },
                {
                    "key": 20027651,
                    "self": "https://BASE_URL/ws/rest/Rob/20027651",
                    "bunkerCategory": {
                        "key": 916945,
                        "self": "https://BASE_URL/ws/rest/BunkerCategory/916945",
                        "bunkerCategoryCode": "FL"
                    },
                    "robFixed": false,
                    "rob": 0.0,
                    "consumption": 0.0
                },
                {
                    "key": 20027663,
                    "self": "https://BASE_URL/ws/rest/Rob/20027663",
                    "bunkerCategory": {
                        "key": 916946,
                        "self": "https://BASE_URL/ws/rest/BunkerCategory/916946",
                        "bunkerCategoryCode": "DO"
                    },
                    "robFixed": false,
                    "rob": 0.0,
                    "consumption": 0.0
                }
            ]
        },
        {
            "key": 20027584,
            "self": "https://BASE_URL/ws/rest/EventLog/20027584",
            "event": {
                "key": 1000051,
                "self": "https://BASE_URL/ws/rest/Event/1000051",
                "eventCode": "BRT"
            },
            "robs": [
                {
...
```

The output will consist of four EventLog objects, each containing four robs, making a total of sixteen robs (calculated by multiplying the number of event logs by four bunker categories). By adding up all the consumption attributes, you can get the total consumption per leg


# Market Index Integration API

**A market index integration** will allow you to continuously feed the Dataloy VMS with updated market rates. From this data, Dataloy VMS can calculate accurate rates automatically, removing cumbersome manual work and reducing the risk of errors.

{% hint style="info" %}
At this point in time, only Market Indices of type TC Rate is used for automatic calculations. Indices of other types will be for information only.
{% endhint %}

The [MarketIndex](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index) entity is a simple object; a name, unique code property, and a list of [MarketIndexValues](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index-value). The MarketIndexValues consists of a date from which it is valid from, a date to which it is valid to, a type signifying if it is current or archived, and a numeric value.


# TC Rate Market Indices

## Calculation overview

When making changes to a TC Rate Market Index - by adding or editing a MarketIndexValue - the following related objects will be recalculated:

* [MarketIndexValue](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index-value)
* [MarketIndex](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index) (validation only)
* [MarketIndex](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/market-index)&#x20;
  * Any custom market index that have the market index you are editing of adding a market index value to will be recalculated if all other market indices in the custom market index has been updated today
* [TcRate](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/tc-rate)
* [TcDuration](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/tc-duration)
* [Tc](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/tc)
* [Offhire](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/offhire)
* [Voyage](https://dataloy-systems.stoplight.io/docs/dataloyModel/model/schemas/voyage)

Recalculation is triggered by a **POST** or **PUT** request on the **MarketIndexValue** endpoint. The scope of objects being recalculated is limited by the **validFrom** date on the **MarketIndexValue**; such that, for instance, a voyage that ends before the **validFrom** date is not recalculated.

**DELETE** requests do not trigger a recalculation at this time. Validation will still run when deleting, and deleting a market index value for a market index that is part of a custom market index is not allowed.

## Workflow

### **Step 1: Bulk Updating Forward Estimates/Rates**

In order to update multiple index values at once, it is recommended to use the [BulkUpdateIncrement](/api-release-8.25/user-guides/enterprise-functionality/bulk-update-increment) feature.&#x20;

{% hint style="warning" %}
While it is possible to trigger all recalculations at once, it is **highly** recommended to add the header *disablebl* with value set to *true* when using the BulkUpdateIncrement feature on MarketIndexValues. This is in order to mitigate calculation costs, and concurrency problems for objects with overlapping.
{% endhint %}

Example:

```
https://{host}/ws/rest/MarketIndexValue/bulkUpdateIncrement
```

```json
[
  {
    "key":{marketIndexValueKey1},
    "validFromDate": "2026-03-01T00:00:00",
    "validToDate": "2026-03-31T00:00:00",
    "marketIndexValue": 5300
  },
  {
    "key":{marketIndexValueKey2},
    "validFromDate": "2026-04-01T00:00:00",
    "validToDate": "2026-04-30T00:00:00",
    "marketIndexValue": 6400
  },
  {
    "key":{marketIndexValueKey3},
    "validFromDate": "2026-01-01T00:00:00",
    "validToDate": "2026-04-30T00:00:00",
    "marketIndexValue": 7000
  },
  {
    "key":{marketIndexValueKey4},
    "validFromDate": "2026-05-1T00:00:00",
    "validToDate": "2026-05-31T00:00:00",
    "marketIndexValue": 7100
  }
]
```

### **Step 2: Updating todays MarketIndexValue**

We can now update todays MarketIndexValue, and trigger a recalculation of all related objects.&#x20;

#### **Option A: PUT on existing MarketIndexValue**

```
https://{host}/ws/rest/MarketIndexValue/{key}
```

```json
{
    "marketIndexValue": 10250
}
```

#### **Option B: POST a new MarketIndexValue**

```
https://{host}/ws/rest/MarketIndexValue
```

```json
{
    "marketIndex": {marketIndexCode},
    "marketIndexValue": 10400,
    "validFromDate": "2025-07-08T00:00:00",
    "publishedDate": "2025-07-08T00:00:00"
}
```

Posting a market index value without:

* marketIndexValueType :
  * Will default to SPOT if either&#x20;
    * ValidFromDate is null
    * validToDate is null
    * ValidFromDate == ValidToDate
  * Else it will get FORWARD
* ValidFromDate
  * If market index value is SPOT
    * Will use ValidToDate
  * Else will fail at validation since valid from date is required
* ValidToDate
  * If market index value is SPOT
    * Will use ValidFromDate
  * Else will fail at validation since validToDate is required
* PublishedDate
  * If market index value is SPOT
    * Sets PublishedDate = ValidFromDate
  * Else
    * Todays date at 00:00 UTC+0


# Left join in API queries

The default behavior when an API query is executed is to put in right join the relationship between objects. From DLP 4.0.0 is possible specify in the filters of the API URL query to use left join instead of the right join.

For instance the following API query: [http://platform-dev.dataloy.com/ws/rest/Cargo?pageNumber=1\&limit=50\&filter=voyage.voyageHeader.isBudget(EQ)0\&filter=(OR)\&filter=voyage(NULL)](http://localhost:8080/ws/rest/Cargo?pageNumber=1\&limit=5\&filter=voyage%2B.voyageHeader%2B.isBudget\(EQ\)0\&filter=\(OR\)\&filter=voyage\(NULL\))

generates the following SQL query:

```
SELECT t0.CARGO_ID AS c0
FROM TBL_CARGO t0 JOIN TBL_VOYAGE t1 ON (t0.VOYAGE_ID = t1.VOYAGE_ID) JOIN TBL_VOYAGE_HEADER t2 ON (t1.VOYAGE_ID = t2.VOYAGE_ID)
WHERE ((t2.IS_BUDGET = 0) OR (t0.VOYAGE_ID IS NULL))
```

That will not return cargoes with voyages null.

Instead if the following query is executed:&#x20;

[http://platform-dev.dataloy.com/ws/rest/Cargo?pageNumber=1\&limit=50\&filter=voyag&#x65;**+**.voyageHeade&#x72;**+**.isBudget(EQ)0\&filter=(OR)\&filter=voyage(NULL)](http://localhost:8080/ws/rest/Cargo?pageNumber=1\&limit=5\&filter=voyage%2B.voyageHeader%2B.isBudget\(EQ\)0\&filter=\(OR\)\&filter=voyage\(NULL\))

encoded (+ become %2B):

[http://platform-dev.dataloy.com/ws/rest/Cargo?pageNumber=1\&limit=50\&filter=voyag&#x65;**%2B**.voyageHeade&#x72;**%2B**.isBudget(EQ)0\&filter=(OR)\&filter=voyage(NULL)](http://localhost:8080/ws/rest/Cargo?pageNumber=1\&limit=5\&filter=voyage%2B.voyageHeader%2B.isBudget\(EQ\)0\&filter=\(OR\)\&filter=voyage\(NULL\))

generates the following SQL query:

```
SELECT t0.CARGO_ID AS c0
FROM TBL_CARGO t0 LEFT JOIN TBL_VOYAGE t1 ON (t0.VOYAGE_ID = t1.VOYAGE_ID) LEFT JOIN TBL_VOYAGE_HEADER t2 ON (t1.VOYAGE_ID = t2.VOYAGE_ID)
WHERE ((t2.IS_BUDGET = 0) OR (t0.VOYAGE_ID IS NULL))
```

It will return also cargoes with voyage null.

The same concept is used with **sort**:

Executing this query:

[http://platform-dev.dataloy.com/ws/rest/Cargo?sort=voyage.voyageHeader.referenceNo(AS)](http://localhost:8080/ws/rest/Cargo?sort=voyage%2B.voyageHeader%2B.referenceNo\(AS\))

the following SQL query is executed:

```

SELECT  t0.CARGO_ID  FROM TBL_CARGO t0
     JOIN TBL_VOYAGE t2
    ON (t0.VOYAGE_ID = t2.VOYAGE_ID)
     JOIN TBL_VOYAGE_HEADER t3
    ON (t2.VOYAGE_ID = t3.VOYAGE_ID)
    ORDER BY t3.REFERENCE_NO
```

Instead running the following query:

[http://platform-dev.dataloy.com/ws/rest/Cargo?sort=voyag&#x65;**%2B**.voyageHeade&#x72;**%2B**.referenceNo(AS)](http://localhost:8080/ws/rest/Cargo?sort=voyage%2B.voyageHeader%2B.referenceNo\(AS\))

the following SQL query is executed:

```
SELECT  t0.CARGO_ID  FROM TBL_CARGO t0
     LEFT JOIN TBL_VOYAGE t2
    ON (t0.VOYAGE_ID = t2.VOYAGE_ID)
     LEFT JOIN TBL_VOYAGE_HEADER t3
    ON (t2.VOYAGE_ID = t3.VOYAGE_ID)
    ORDER BY t3.REFERENCE_NO
```


# Enterprise functionality


# Versioning

**From**[ **version 2.10**](https://dataloy-cloud.atlassian.net/wiki/spaces/ARN/pages/923404364/Dataloy+API+2.10+Release+Notes) it is possible to have multiple versions of Dataloy API deployed on an application server. New API functionalities can be utilized for certain clients while at the same time continue to use older API versions for other clients. This usage of the system can remain until all clients are tested and working with the latest Dataloy API version. The API version is specified in the URL.

**Latest Version**

The latest version of Dataly API deployed at a customer's application server remains available at:&#x20;

| `http://[ip]:[port]/ws/rest` |
| ---------------------------- |

Older versions can be located at **ws/rest/version-number**. For example, if version 2.10.0 is deployed it will be found at:

| `http://[ip]:[port]/ws/rest/6.38.0` |
| ----------------------------------- |


# Endpoint access control

Is possible restrict access to any endpoint.

In order for a user to get access to a given API Endpoint, the user must belong to a SecurityRole that has a SecurityPermission for the API Endpoint.

<figure><img src="/files/lj2NBxrsEJFPqpSyaWF5" alt=""><figcaption></figcaption></figure>

he endpoint access control is done also against the objects requested using  the ***fields*** JSON in the HTTP  Header. So for instance if the endpoint Vessel.GET is present and the user  does not belong to a SecurityRole that has a SecurityPermission for the Vessel.GET endpoint, requesting the Voyage resource specifying the following JSON in the fields parameter will get unauthorized (HTTP 401):

```
{ 
   "vessel":{ 
      "vesselName":"*",
      "auxEngine":"*"
   }
}
```

\
If the same user requests with the following JSON, it will get access because vesselName attribute is part of the minimal view of Vessel resource:

```
{ 
   "vessel":{ 
      "vesselName":"*"
   }
}
```

The same access control is performed when a WebhookSubscription is requested. If the user tries to subscribe for an object that has an Endpoint in the system, the subscription will be created only if the user can access to the Endpoint, otherwise Bad request (HTTP 400) exception will be thrown. <br>

To create a new Endpoint it has to be used the endpoint /ws/rest/Endpoint posting a JSON like this:

```
{
    "resourceName": "Vessel",
    "path": ".",
    "httpMethodType": "GET"
}
```

To create a new SecurityPermission it has to be used the endpoint /ws/rest/SecurityPermission posting a JSON like this:

```
{
    "endpoint": 335928937,
    "permissionName": "Bank.GET",
    "permissionType":  335343886
}
```

To create a new SecurityRole. Post the following JSON to /ws/rest/SecurityRole:

```

{
    "roleName":"testRole"  
}
```

To add a SecurityPermission to a SecurityRole. Post the following JSON to /ws/rest/SecurityRole:

```

{
    "securityPermissions": [
        {
            "key":335928939
        }
    ]
     
}
```

To add a SecurityRole to a User. Post the following JSON to /ws/rest/SecurityRole:

```

{
     
    "securityRoles": [
        {
            "key":335927922
        }
    ]
}
```


# Data access control via target object

Through DataControl objects is possible control the access to data  of the logged user for a given object connected to the target.&#x20;

For instance if we want to give access only to voyages connected with the business units that the user belong to, a DataControl object like this has to be posted:

```

{
    "matcherTarget": "BusinessUnit",
    "matcherAttributeTarget": "users.key",
    "objectName": "Voyage",
    "attribute": "voyageHeader.businessUnit"
}
```

* **matcherTarget** defines the Dataloy object that has to be used as target object
* **matherAttributeTarget** defines the attribute in the object target that links the object with the user
* **objectName** the Dataloy object that has to be applied the access control
* **attribute** the attribute name that link the  Dataloy object with the target object


# Data access control via target object and security role

Through the DataControl object it is possible to control data access for a target user(s) for a given object connected to the target by checking if the user(s) belongs to a given role.

For example, if we want to limit access for the captain of a vessel to only be able to view voyages of their vessel, a DataControl object like this has to be posted:

```
{
    "matcherTarget": "User",
    "matcherAttributeTarget": "key",
    "objectName": "Voyage",
    "attribute": "voyageHeader.vesselCodes.masterUser",
    "dataControlRoleValues":[
    	{"role": "MASTER_ONLINE_VESSEL"}
    ]
}
```

* **matcherTarget** defines the Dataloy object that has to be used as target object
* **matcherAttributeTarget** defines the attribute in the matcherTarget object that has to be used against the attribute of the object (objectName)
* **objectName** the Dataloy object that has to be applied the access control
* **attribute** the attribute name that links the Dataloy object with the target object
* **dataControlRoleValues** list of SecurityRole that the DataControl will be applied

In the above example if an User that belong to the SecurityRole "MATER\_ONLINE\_VESSEL" make a query to the endpoint Voyage, the server will return only the voyages that has voyageHeader.vesselCodes.masterUser = {the user that made the query}




---

[Next Page](/llms-full.txt/1)

