Maasplassen API-Doc - V2

The Maasplassen-API is the machine interface of the Maasplassen-application initiated by the Tourism agency VVV Midden Limburg in conjunction with the Province Limburg.
At this moment only a limited number of endpoints are available and the service is still in ßeta.


# Changelog
v2.7    Removed async and defer from Javascript Injection script tag.
v2.6    Added language support to /fleet endpoint and  javascript-injector
v2.5    Added 'overige' to the filter list of /fleet endpoint
v2.4    Payload for fleet availability update should be urlencoded
v2.3    Added Javascript Injection-section
v2.2    + Added extended company information at
          the /company/{id}/reviews endpoint
        + added /rentals-endpoint
v2.1    Revised the CTA field in the /fleet/{date?}
        endpoint to be an object.
v2.0    Initial commit

The Administrator and first contact for content-related questions is the VVV. For technical questions and bugs please send a message to the developer of the application: support@vannut.nl

During development we have a temporary URL on which the application is served. Please use this 'sandbox' as a playground for your API-requests.
Testing: http://maasplassen.vannut.net
Production: https://secure.maasplassen.com

Authentication

//- example request URL
https://secure.maasplassen.com/api/v2/endpoint?apikey=pub.0b72a259-db89-452f-8b8a-34892a942179
    

Every request to our api-endpoints need to be accomponied by an API-key as URL parameter. Associated companys can register their own api-key within the backoffice. Third party developpers can request an API key with the adminstrator.

Per definition an API-key is a public key; therefore every api-key starts with pub.* and consists of numbers and letters. Dashes and spaces are ignored, so they can be used to make the key better human readable. Please bear in mind that spaces are converted if used in an URL.

In our application we have two different levels within our endpoints. 'Simple' endpoints (mostly GET-requests) can be called with solely the apikey=… query parameter.

<?php
//- example request URL with hmac signature
    $apikey = 'pub.0b72a259-db89-452f-8b8a-34892a942179';
    $secret = 'sk.9isI6XLkRutLtjwRHZUc4I7Nw3tdf6r6R5KZ3ChZDxb6yU65Q6fGr';

//- payload = json-string containing the changes to be made
    $payload = "{'some':'json data','which':'needs to be processed'}";
    $hmac = hash_hmac('sha256', $payload, $secret);
    // 6dd69b92d7e7927680a459740efc9167feddde57d310afb2e2ed3191b9bfb1d4

//  or, instead of the payload the endpointURI will be used
    $hmac = hash_hmac('sha256', '/api/v2/endpoint/', $secret);
    // 18501fba8c6072b1de07602eddf4ce7f9a553f8de8c2317d1a23908779850346



//- request
POST    /api/v2/endpoint?apikey=pub.0b72a259-db89-452f-8b8a-34892a942179
        payload = $payload;
        hmac = $hmac;
    

Other endpoints need additional authorization to verify the authenticity of the request by signing the/a payload by means of a HMAC,Hash-based Message Authentication Code , signature. This signature is in the form of a algorithmic hash based on the Secure Hash Algorithm (SHA256). Most programming language provide a helper function to provide these hashes. To create this hash you and our systems need to have a secret key which is associated with your apikey. Due to its nature, this key needs to remain secret! A secret key starts with sk.*.

The HMAC signature needs to be calculated over a string. If the payload parameter is present this JSON-string is the string which needs to be signed. If not present the endpoint without http_host is the string to be signed.

Response objects

{
    "meta": {
        "status": 200,
        "msg": "....", //optional
        "results": 6,
        "owner":"test.key"
        },
    "data": { ... }
}
//- example of an error-response
{
    "error": {
        "type": "VanNut\Exceptions\ApiKeyDisabledException",
        "message": "This API-key is disabled! ",
        "code": 503
        }
}

We JSON. So whenever possible we use JSON to structure our data and we expect your requests to use JSON whenever data is needed.
Eg the payload needed with some endpoints is a JSON data string which contains the changes to be committed to our system.

Every return response of our server is in the form of a JSON-object containing data and meta. We hope we do not need to explain the difference ;)

If your request produces an error, an error object will be returned containing more verbose information what went wrong.

Fleet management

Core part of the Application is the management of the entire (rental) fleet of the Maasplassen. With these endpoints you will be able to update the fleet and its availability.

//Response-object
{
    "meta": {......},
    "data": {
        "boten": [
            {
                "bootnaam": "Valk met motor",
                "type": "zeilboot",
                "beschrijving": "De klassieker ... binnenstad in kunt.",
                "max_personen": "5",
                "ext_id": "91", // Your ID
                "bootid": "6",  // Our ID
                "aandrijving": "windbb",
                "bedrijf": {
                    "naam": "Van Nut",
                    "url": "http:\\/\\/vannut.nl",
                    "email": "wijzijn@vannut.nl",
                    "id": "1",
                    "review_cijfer": "5.00",
                    "review_sterren": ".. html ..."
                },
                "beschikbaarheid": [
                    {
                        "desc": "Hele dag ",
                        "cents": 9500
                    }
                ],
                "cta": {
                  "action": "http://...",
                  "type": "direct"
                },
                "afbeelding": [
                    "http://maasplassen.vannut.net/assets/...",
                    "http://maasplassen.vannut.net/assets/...",
                    ...
                ]
            },
            { .... }
        ]
    }
}

updatedget/fleet/{date?}/{lang?}
?apikey=pub.*&filter=zeilboot

Get the availability of (the complete) fleet for the given day.
Public API-key

url date The date you want to query. Needs to be in ISO8601 format: yyyy-mm-dd. Defaults to today
url lang Which language do you want to retrieve the information in?
Allowed: ['nl', 'de'] Defaults to nl
query filter Comma-separated list to filter the boat by type. Allowed entries: ['zeilboot', 'motorboot', 'sloep', 'kajuitboot', 'peddelboot','overige'] (sorry not available in english :( ) (optional, defaults to all)
query apikey Your public api-key

The response object contains the complete information needed to produce a nice fleet-rack or overview.
The 'beschikbaarheid' object contains the available options which customers can reserve.

According to the language setting the info is returned in the appropriate locale. If not present in the database, or incorrect language, it fallsback to nl.

The CTA-object contains the Call to action for this boat. As we have different types of companys we also have different type of actions. The action is always a link to our servers because we want to track the amount of clicks. After hitting our servers it wil return an action.

direct the link in cta.action refers to a page where visitors can directly book the selected boat.
email a mailto:link
info refering to a page with general contact information of the company

The link-click is being registered in the application with your ID linked to your API-key.

A boat can have zero or more pictures in the 'afbeelding'-object.

In the meta-object we inject some alternative dates which you can use to redirect customers when there is no availability for a certain boat/day combination.
Furthermore it holds an 'filter'-object containing the filters ;)

get/fleet/{boatid}/images
?apikey=pub.*

Retrieve images for a boat.
public API-key

//response-object
{
    "meta": { ... },
    "data": [
        {
            "url": "http://maasplassen.vannut.net/assets/...",
            "title": "This is a title", //optional
            "bestandsnaam": "antaris.jpg"
        },
        { ... }
    ]
}
url boatid Our unique boatid.
query apikey Your public api-key

Returns all the images stored in our database

Company management

Administer and query (your|a) company and get its information.

get/rentals
?apikey=pub.*

Retrieve every visible rental company in the system.
public API-key

//response-object
{
    "meta": { ... },
    "data": {
        {
            "id": 34,
            "naam": "Company Name"
        },
        { ... }
    }
}
    
query apikey Your public api-key

get/company/{companyid}/reviews
?apikey=pub.*&limit=10

Retrieve reviews of one company.
public API-key

//response-object
{
    "meta": { ... },
    "data": {
        "stats": {
            "aantal": "1",
            "min": "5",
            "gem": "5.0",
            "max": "5"
            },
        "reviews": [
            {
                "created_at": "2015-05-19 12:17:13",
                "cijfer": "5.0",
                "opmerking": "Top bedrijf, denken met je mee. ",
                "naam": "Pipo",
                "mgt_response": null,
                "ico": "... html ...",
                "human": "dinsdag 19 mei 2015"
            },
            { ... }
        ],
        "info": {
            ... company info ...
        }
    }
}
    
url comapnyid The company id.
query limit How many reviews need to be displayed? defaults to 10
query apikey Your public api-key

post/company/{companyid}/stats/{period?}
?apikey=pub.*

Retrieve statistics (CTR/clicks/views).
HMAC signed endpoint URL

//response-object
{
    "meta": { ... },
    "data": {
        "views": {
            "test.Postman": "2",
            "vvv.Portaal": "209"
        },
        "clicks": {
            "vvv.Portaal": "2"
        },
        "ctr": "0.94",
        "graph": " ... json-string ..."
    }
}
url companyid The company id.
url period What period do you want to calculate?
post hmac The endpoint hashed with your secret key.
query apikey Your public api-key

This endpoint returns statistical information on the outgoing registrations of the boats associated with the company in the url.
Views and clicks are split up by the owners of the API-keys to identify the source.

In our backend we check if the requesting API-key belongs to the company which data is being displayed. So it's not possible to retrieve the statistics from other company's. (unless your api-key is registered as a 'superkey').

post/company/{companyid}/fleet/
?apikey=pub.*

Retrieve the complete fleet of this company.
HMAC signed endpoint URL

//response-object
{
    "meta": { ... },
    "data": [
        {
            "id": "6",  // our ID
            "ext_id": "91", // Your ID
            "naam": "Valk met motor",
            "type": "zeilboot",
            "zichtbaar": "1",
            "updated_at": "2015-03-30 12:29:44"
        },
        { ... }
    ]
}
    
url companyid The company id.
post hmac The endpoint hashed with your secret key.
query apikey Your public api-key

In our backend we check if the requesting API-key belongs to the company which data is being displayed. So it's not possible to retrieve the statistics from other company's. (unless your api-key is registered as a 'superkey').

post/company/{companyid}/boat/{id}
?apikey=pub.*

Retrieve boat info.
HMAC signed endpoint URL

//response-object
{
    "meta": { ... },
    "data": {
        "updated_at": "2015-05-13 10:56:44",
        "id": "7", // Our ID
        "ext_id": "98", // Your ID
        "ext_referentie": "antaris-520", // Your  reference
        "naam": "Antaris 520",
        "type": "sloep",
        "zichtbaar": "1",
        "beschrijving": "De Antaris ... worden.",
        "lengte": "5.20",
        "max_personen": "4",
        "aandrijving": "binnenboord",
        "standaardPrijs": [
            {
                "desc": "Hele dag varen",
                "cents": 15000
            },
            { ... }
        ]
}
    
url companyid The company id.
url boatid Our unique boatid.
post hmac The endpoint hashed with your secret key.
query apikey Your public api-key

The response contains the current information of the specified boat. Including the standard prizes and our internal boatid which is unique throughout the whole application.

In our backend we check if the requesting API-key belongs to the company which data is being displayed. So it's not possible to retrieve the statistics from other company's. (unless your api-key is registered as a 'superkey').

updatedpost/company/{companyid}/availability/update
?apikey=pub.*

Update the availability of this company.
HMAC signed payload.

//Payload-object
{
    "company":1,
    "availability":[
        {
            "boat":7, // YOUR id
            "date":"2015-03-03",
            "prizes":[
                {
                    "desc":"Beschrijving", "desc_de": "Beschreibung",
                    "cents":4500
                },
                { ... }
            ]
        },
        {
            "boat":7, // YOUR id
            "date":"2015-03-04",
            "prizes":null //- no boats available
        },
        { ... }
    ]
}

//Response-object
{
    "meta": {
        "message": "Availability is updated.",
        "original_payload": {
            ...
        },
        "status": 200,
        "owner": "test.Postman"
    },
    "data": null
}
    
url companyid The company id.
post payload URL_ENCODED JSON string (see aside)
post hmac The payload-string hashed with your secret key.
query apikey Your public api-key
query apikey Your public api-key

The payload post-parameter contains an urlencoded json-string with all the new availability. Per boat-date combination you're allowed to provide one boat-object. If you might supply multple objects for the same combination, the last one would persist. The prizes object is —again— a JSON-object containing the available options for the boat-date combination.

If there aren't any boats available for the boat-date combination you can specify this as a `null` value as the 'prizes'-object. So you actively need to push this 'value' to block all the boats for that day.

You can supply multiple boat-date objects within one request. Bear in mind: if one of the objects is false (eg wrong date, or boat not found) the whole request will be rolledback.
In the result-error-object there will be more information about the first error discovered which triggered the rollback.

Jettys

Spread across the Maasplassen region there are a lot of jetty to which cruise companys can more to sightsee the surroundings. With these endpoints you can query the information about these jettys.

get/jetty
?apikey=pub.*

Retrieve list of all available jettys.
public API-key

//response-object
{
    "meta": { ... },
    "data": {
        "4": {
            "id": "4",
            "naam": "Roerkade",
            "lat": "51.19479615",
            "lon": "5.98381519",
            "lengte": "30",
            "bezet": null
        },
        { ... }
    }
}
    
query apikey Your public api-key

'Bezet' contains the message displayed on the marquee if available. Otherwise the name of the company is displayed. If `null` the jetty is not occupied at time of the request.

post/jetty
?apikey=pub.*

Retrieve list of all available jettys with sensitive information.
HMAC signed endpoint URL

//response-object
{
    "meta": { ... },
    "data": {
        "4": {
            "id": "4",
            "naam": "Roerkade",
            "huidig": null,
            "volgend":  {
                ...
            }
        },
        {...}
    }
}
    
post hmac Your HMAC signature
query apikey Your public api-key

More basic Jetty information as the get jetty request. But this result holds the current and upcoming reservation if available. These `huidig` and `volgend` objects contain the complete (sensitive) reservation information.

Javascript-Injectionupdated

// element inwhich we inject all content
<div id="vloot"></div>
// The remote injection script
<script src="https://secure.maasplassen.com/assets/portaal/latest.js"
        >
        </script>
// calling and initalizing the script
<script type="text/javascript">
    vannut.init({
            apihost: 'https://secure.maasplassen.com ',
            apikey: 'pub.0b72a259-db89-452f-8b8a-34892a942179',
            language: 'nl'
        })
        //.addReview() // OR
        .bootLijst();
</script>

We developped a small js-application with which you can include a availability list and review-engine on your own website. It is designed to be as least intrusive as possible: it load asynchronous and adapts to your stylesheets.

All you need to do is include a remote javascript-file at the end of your page, just before the closing <body> tag.

After this inclusion you,ve got a global object on which you have to run the init() method to init the application with your specific options. Of these the apihost and apikey are mandatory. Without these two parameters the application will throw an error.

After initialization you can either call bootLijst() OR addReview().

{
    target: 'vloot',
    debug: false,
    apihost: false,
    apikey: false,
    taal: 'nl',
    toonAlternatieven: false,
    endpoints: {
        fleet:   '/api/v2/fleet',
        images:   '/api/v2/fleet/%i/images',
        review:   '/api/v2/company/%i/reviews',
        review_add:   '/api/v2/company/addReview',
        bedrijven: '/api/v2/rentals'
    },
    tekst: {
        nl: {
            vind_uw_boot: ' Toon aanbod!',
            sloep: 'Sloep',
            zeilboot: 'Open zeilboot',
            motorboot: 'Motorboot',
            kajuitboot: 'Kajuitboot',
            peddelboot: 'Peddel',
            overige: 'Overige watersporten',
            cta: {
                direct: 'Boek Nu',
                email: 'Email ons',
                info: 'Meer info'
            },
            aandrijving: {
                binnenboord: 'Binnenboord',
                buitenboord: 'Buitenboord',
                electrisch: 'Electrisch',
                wind: 'Wind',
                windbb: 'Wind + hulp',
                spier: 'Spier',
            },
            helaas_niet_beschikbaar: "Helaas is deze boot op deze dag niet beschikbaar.",
            misschien_andere_dag: "Misschien een andere dag?",
            afbeeldingDisclaimer: 'Aan de getoonde afbeeldingen kunnen geen rechten ontleend worden.',

            review_intro: "Selecteer hierboven een bedrijf om een review achter te laten.",
            review_waarom: 'Geef hier (optioneel) aan waarom u deze waardering geeft.',
            wat_vond_u_van: "Wat vond u van deze verhuurder?",
            uw_naam: "Uw naam",
            uw_review: "Uw review",
            versturen: ' Versturen',
            velden_leegmaken: ' Velden leegmaken',
            bedankt_verder_url: '/',
            bedankt_verder: 'Verder ... »',
            waardering: {
              ster5: '***** Geweldig',
              ster4: '**** Best goed',
              ster3: '*** goed',
              ster2: '** Kan beter',
              ster1: '* Slecht'
            }
        },
        de: {
            vind_uw_boot: ' Angebote anzeigen!',
            sloep: 'Schaluppe',
            zeilboot: 'Segelboot',
            motorboot: 'Motorboot',
            kajuitboot: 'Kajütboot',
            peddelboot: 'Paddel-Boot',
            overige: 'Andere Wassersport',
            cta: {
                direct: 'Jetzt buchen',
                email: 'Mailen Sie uns',
                info: 'Weitere Infos'
            },
            aandrijving: {
                binnenboord: 'Innenbord',
                buitenboord: 'Aussenbord',
                electrisch: 'Elektrisch',
                wind: 'Wind',
                windbb: 'Wind + Hilfsmotor',
                spier: 'Muskel',
            },
            helaas_niet_beschikbaar: "Leider ist dieses Boot an diesem Tag nicht verfügbar",
            misschien_andere_dag: "Vielleicht an einem anderen Tag?",
            afbeeldingDisclaimer: 'Die gezeigten Bilder sind nicht rechtsverbindlich.',

            review_intro: "Wahlen Sie hier oben ein Unternehmen.",
            review_waarom: 'Optional: warum diese Bewertung?',
            wat_vond_u_van: "Was halten Sie von diesem Geschäft?",
            uw_naam: "Ihre Nahme",
            uw_review: "Ihre Rezension",
            versturen: ' Schickem',
            velden_leegmaken: ' Felder leeren',
            bedankt_verder_url: '/',
            bedankt_verder: 'Weiter ... »',
            waardering: {
              ster5: '***** Super!',
              ster4: '**** ziemlich gut',
              ster3: '*** gut',
              ster2: '** könnte besser sein',
              ster1: '* schlecht'
            }
        }
    }
}

Almost everything is adjustable. Mostly the defaults are suitable for most situations. Just look at the object on the right; to see the default.
When willing to change one parameter; you only have to supply that parameter in the init() function. The remaining paramters will stay at their default.

You have to set the apihost and apikey. And most of the time you will want to add the language-parameter as well.