NAV Navbar
  • Documentation
  • Authentication
  • Availability check API
  • Order API
  • Errors
  • Documentation

    Please note, this documentation is not exhaustive, and other optional values may be returned in responses.

    If you have questions or found errors, get in touch at dev@porterbuddy.com.

    Overview

    Porterbuddy is a last mile delivery service platform. Customers of Porterbuddy can place delivery orders using this api.

    The following describes the necessary steps to do a delivery using Porterbuddy:

    1. Your retailer solution: Fetch delivery availability
    2. End user: Choose delivery time
    3. Your retailer solution: Place delivery order
    4. Porterbuddy: Deliver the parcels at the requested time

    Time

    All timestamps requires timezone to avoid ambiguity.

    Availability

    An availability object is an entity that combines pickup address, delivery address, and delivery time. To be able to guarantee our ability to fulfill an order, you first need to obtain an availability entity before submitting an order for the requested time.

    Order

    The order contains all information needed to deliver to the end user. This includes addresses and delivery time, but also the availability for the package for pick up and requirements for identification, etc.

    Testing the API

    If you want to test the API, you can send a request to dev@porterbuddy.com to receive a test API key.

    Get an API key

    To get an API key for use in production, you first have to register as a user and customer at Porterbuddy. Currently, we only support payment by invoice. As a result the process of getting access is as follows:

    1. Go to porterbuddy.com and register a user (of type business)
    2. Contact dev@porterbuddy.com to enable payment by invoice
    3. Receive your API key

    Implementation Hints

    We try to keep this API as stable as possible. However, implementing new services or features sometimes make changes necessary, for example adding new properties to API objects. To lower the risk of such a change breaking your integration, we advise to only define the properties of API responses your integration needs and always ignore unknown properties in received json objects. This is the default behaviour in Javascript (due to Javascript not being typed anyway) and Typescript when representing received API responses via interfaces. When using Jackson to implement JSON APIs in Java, the easiest way to achieve this is to use the annotation @JsonIgnoreProperties(ignoreUnknown=true)on classes representing API response data.

    Authentication

    An authenticated request includes the x-api-key header:

    curl "https://api.porterbuddy.com/..."
      -H "x-api-key: <your_api_key>"
    

    Make sure to replace <your_api_key> with your API key.

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

    x-api-key: <your_api_key>

    Availability check API

    To verify that PorterBuddy can deliver according to your preferences you need to do an availability request. This will verify address details and return possible delivery windows. Note that even when the endpoint returns statuscode OK (200), the delivery windows array could be empty due to no delivery being possible with the specified pickup windows, or no more capacity being available.

    POST https://api.porterbuddy.com/availability

    Example Request:

    curl \
      -X POST 'https://api.porterbuddy.com/availability' \
      -H 'Content-Type: application/json' \  
      -H 'x-api-key: <your_api_key>' \
      -d '{
            "pickupWindows": [
                {"start": "2021-02-12T10:00+01:00", "end": "2021-02-12T18:00+01:00"},
                {"start": "2021-02-13T10:00+01:00", "end": "2021-02-13T18:00+01:00"}
            ],
            "originAddress": {
                "streetName": "Keysers Gate",
                "streetNumber": "3",
                "postalCode": "0165",
                "city": "Oslo",
                "country": "Norway"
            },
            "destinationAddress": {
                "streetName": "Høyenhallveien",
                "streetNumber": "25",
                "postalCode": "0678",
                "city": "Oslo",
                "country": "Norway"
            },
            "recipient": {
                "email": "testemail+recipient@porterbuddy.com",
                "phoneCountryCode": "+47",
                "phoneNumber": "65127865"
            },
            "products": [ "delivery" ],
            "parcels": [
                {
                    "widthCm": 1,
                    "heightCm": 40,
                    "depthCm": 1,
                    "weightGrams": 2000
                }
            ]
        }'
    

    Example response:

    {
        "originResolvedAddress": {
            "streetName": "Keysers Gate",
            "streetNumber": "3",
            "postalCode": "0165",
            "city": "Oslo",
            "country": "Norway",
            "position": {
                "latitude": 59.9169844,
                "longitude": 10.7411912
            }
        },
        "destinationResolvedAddress": {
            "streetName": "Høyenhallveien",
            "streetNumber": "25",
            "postalCode": "0678",
            "city": "Oslo",
            "country": "Norway",
            "position": {
                "latitude": 59.9032646,
                "longitude": 10.811598
            }
        },
        "deliveryWindows": [
            {
                "start": "2021-02-12T8:45+01:00",
                "end": "2021-02-12T10:00+01:00",
                "product": "express",
                "price": {
                    "fractionalDenomination": 14900,
                    "currency": "NOK"
                },
                "expiresAt": "2021-02-12T08:30+01:00",
                "token": "eBZzhfRfeAcqwbJEKhEQ==:UflRB0IJo4yUiccm/nCavg==:TPYPZz17hGsmAestkU5s6hUL+hzps746pPg54LHlNPHVjy4paUmndzVbW4u0miDNkt4NZHZ+u8NlhzHNLr+qHrbAiCsCNU6R+WmFsjrS5z/ivGnZjH049/mfACXC1a/rYb7NnT9VAEwPlg==",
                "displayPrice": {
                    "fractionalDenomination": 9900,
                    "currency": "NOK"
                }
            },
            {
                "start": "2021-02-12T10:00+01:00",
                "end": "2021-02-12T12:00+01:00",
                "product": "delivery",
                "price": {
                    "fractionalDenomination": 19900,
                    "currency": "NOK"
                },
                "expiresAt": "2021-02-12T08:30+01:00",
                "token": "RfeAcqwbJEKhEQ==:IJo4yUiccm/nCavg==:TPYPZz17hGsmAestkU5s6hUL+hzps746pPg54LHlNPHVjy4paUmndzVbW4u0miDNkt4NZHZ+u8NlhzHN6R+WmFsjrS5z/ivGnZjH049/mfACXC1a/rYb7NnT9VAEwPlg==",
                "displayPrice": {
                    "fractionalDenomination": 14900,
                    "currency": "NOK"
                }
            }
        ]
    }
    

    Arguments

    Parameter Required Type Default Description
    originAddress Yes Address none The pick up location for the merchandise
    destinationAddress Yes AvailabilityDestinationAddress none The destination for the merchandise
    recipient No AvailabilityRecipient none The contact details of the delivery recipient
    pickupWindows Yes List<Window> none The windows when the package is available for pick-up. We recommend sending wide windows and for multiple days. Ex: If the package is ready for pick up from 3pm on monday and the store closes at 7pm, the first window will be 3pm-7pm the first day, and the following windows should probably be the opening hours for the store the next days.
    products No List [ delivery, express ] The name of the product needed. For most partners this is delivery and express. Multiple products here will result in windows in the list for each product. Each window has a 'product' attribute which signals which product this is for.
    parcels Yes List<Parcel> none The list of parcels that you want to transport. This will affect which couriers can fulfill the delivery. A smaller car cannot drive packages that won't fit in it's trunk.
    additionalInfo no Object null Object reserved for additional information. This argument is intended to be provided by the checkout widget and needs to be passed-through as is, without further modifications.

    Availability Destination Address

    Parameter Required Type Default Description
    streetName No String none Name of the street
    streetNumber No String none Number of the street. Including any letters. Ex: 10d
    postalCode Yes String none The postal code of the address
    city No String none The city of the address
    country Yes String none The country of the address

    Availability Recipient

    Parameter Required Type Default Description
    email No String none Email
    phoneCountryCode No String +47 Country code for the phone number
    phoneNumber No String none Phone number

    Response

    Parameter Type Description
    originResolvedAddress Resolved Address Resolved origin. We will resolve the origin against Google\'s APIs. The exact details we find will be returned here.
    destinationResolvedAddress Resolved Address Resolved destination. Like with the origin, we will try to resolve the exact details. The result will be returned here.
    deliveryWindows List<DeliveryWindow> The available windows for the destination. This is tied to the pick up windows given in the request, so any changes to those will affect these windows as well.
    consolidatedWindow ConsolidatedDeliveryWindow Available window for the destination. Present if the recipient field was present in the request and the customer has already placed one or more orders within one of the delivery windows.

    Resolved Address

    Parameter Required Type Default Description
    streetName Yes String none Name of the street
    streetNumber Yes String none Number of the street. Including any letters. Ex: 10d
    postalCode Yes String none The postal code of the address
    city Yes String none The city of the address
    country Yes String none The country of the address
    position Yes Position (lat/long) none The exact position of the address in longitude/latitude

    Delivery Window

    Parameter Type Description
    start DateTime The start of the window
    end DateTime The end of the window
    product String The product type this window is for. Example: delivery or express
    price Price The price given for the specific window
    displayPrice Price The display price given for the specific window, calculated based the store's configured base display price. Used to show the end customer a price different from the actual price. Only returned when a base display price is configured.
    expiresAt DateTime After this time this window should not be shown as an option. Either remove the window or do a full refresh of the availability.
    token String The token is to be sent back when placing and order. It makes sure that the window and price that was offered for availability at that specific point in time is what is registered on the order.
    consolidated Boolean If true, there is another order present for the same customer with that window, so the orders can be consolidated.

    Consolidated Delivery Window

    Parameter Type Description
    start DateTime The start of the window
    end DateTime The end of the window
    product String The product type this window is for. Example: delivery or express
    price Price The price given for the specific window
    displayPrice Price The display price given for the specific window, calculated based the store's configured base display price. Used to show the end customer a price different from the actual price. Only returned when a base display price is configured.
    expiresAt DateTime After this time this window should not be shown as an option. Either remove the window or do a full refresh of the availability.
    token String The token is to be sent back when placing and order. It makes sure that the window and price that was offered for availability at that specific point in time is what is registered on the order.
    consolidated Boolean If true, there is another order present for the same customer with that window, so the orders can be consolidated.

    Price

    Parameter Type Description
    fractionalDenomination Integer The price in the lowest denominator. Ex: 1 USD = 100 fractionalDenomination (cents)
    currency String The currency specified. Usually "NOK".

    Order API

    Place an order

    To place an order you need to know the destination, origin as well as the times chosen by the user and the times the package is available for pickup.

    POST https://api.porterbuddy.com/order

    Example request:

    curl -X POST \
      https://api.porterbuddy-test.com/order \
      -H 'x-api-key: <your_api_key>' \
      -H 'Content-Type: application/json' \
      -H 'Idempotency-Key: <your idempotency key>' \
      -d '{
             "origin": {
                "name": "Nils Johansen (Sender)",
                "address": {
                    "streetName": "Keysers Gate",
                    "streetNumber": "3",
                    "postalCode": "0165",
                    "city": "Oslo",
                    "country": "Norway"
                },
                "email": "testemail+sender@porterbuddy.com",
                "phoneCountryCode": "+47",
                "phoneNumber": "65127865",
                "pickupWindows":[{"start":"2021-02-12T10:00+02:00", "end":"2021-02-12T12:00+02:00"}]
            },
            "destination": {
                "name": "Roger Olsen (Recipient)",
                "address": {
                    "streetName": "Høyenhallveien",
                    "streetNumber": "25",
                    "postalCode": "0678",
                    "city": "Oslo",
                    "country": "Norway"
                },
                "email": "testemail+recipient@porterbuddy.com",
                "phoneCountryCode": "+47",
                "phoneNumber": "65789832",
                "deliveryWindow":{
                    "start":"2021-02-12T10:00+02:00", 
                    "end":"2021-02-12T12:00+02:00",
                    "token": "lpi4I5mS9VfhO4NBQcAygg==:8otbBDjbGFd/PmSNniiwGw==:05OcfWoG3zfFEoy5GgyPkls71hnCk9baxenjogT/6+Yn3Pp7NUUFAEaq0mgfKGsJWClgCCy7hKuZCcf7Mn/C7DiTm8H8k03A/O4ebnyC85xeeRxf43ON9+ce64HnMqTFHLvozikpOFfB0sPYO3wmQZoqwnyI4H/+39aSLf+evYtR53fqBU+mFgPLr0/rhcTQ/jfdXQmZ6UZ5KYzwMHBkZ4Kb75FuEdP7y/90oWfHmGNOIdodcrR6zs1OGXRcpA1T"
                },
                "verifications": {
                    "minimumAgeCheck": 16,
                    "leaveAtDoorstep": false,
                    "idCheck": true,
                    "requireSignature": false,
                    "onlyToRecipient": true
                }
            },
            "parcels" : [
                {
                    "description": "Shoes",
                    "widthCm": 1,
                    "heightCm": 40,
                    "depthCm": 1,
                    "weightGrams": 2000,
                    "parcelShipmentIdentifier": "12345"
                }
            ],
            "product": "delivery",
            "courierInstructions": "Test",
            "shipmentIdentifier": "12345"
        }'
    

    Example response:

    {
      "orderId": "3520",
      "_links": {
        "self": {
            "href": "https://api.porterbuddy-test.com/order/3520"
        },
        "labelInfo": {
            "href": "https://api.porterbuddy-test.com/order/3520/label"
        },
        "status": {
            "href": "https://api.porterbuddy-test.com/order/3520/status"
        },
        "userInformation": {
            "href": "https://www.porterbuddy-test.com/orders/recipient_tracking/aDpa9ytqp86no9XATds6r2gf"
        }
      }
    }
    

    Arguments

    Parameter Required Type Default Description
    origin Yes Origin none Information about the origin location.
    destination Yes Destination none Information about the destination.
    parcels Yes List<Parcel> none Information about the parcels.
    product Yes String none The product associated with the window chosen.
    orderReference No String none Your internal order reference.
    courierInstructions No String "" A message to the courier about the delivery.
    shipmentIdentifier No Digits[5-20] none Shipping identifier. The 5 last digits will be used as a pickup pin if this is specified.

    Origin

    Parameter Required Type Default Description
    name Yes String none Full name
    address Yes Address none The address where the package will be collected
    email Yes String none Email
    phoneCountryCode No String +47 Country code for the phone number
    phoneNumber Yes String none Phone number
    pickupWindows Yes List<Window> none The available windows to pick up the package. We recommend as large as possible over several days in case the customer wants to change the delivery window.

    Destination

    Parameter Required Type Default Description
    name Yes String none Full name
    address Yes Address none The address where the package will be delivered
    email Yes String none Email
    phoneCountryCode No String +47 Country code for the phone number
    phoneNumber Yes String none Phone number
    bestAvailableWindow No Boolean false IF this is true, find the "best available" window. This might be today or tomorrow, or even the next day if tomorrow is a holiday. To have some idea about when something can be delivered it is always best to verify availability through API.
    deliveryWindow Yes* Window none The agreed upon window to deliver within. This should be a window fetched from the /availability request.
    * This is not required if bestAvailableWindow is used.
    verifications Yes Verifications none The verifications to be performed by the courier.

    Address

    Parameter Required Type Default Description
    streetName Yes String none Name of the street
    streetNumber Yes String none Number of the street. Including any letters. Ex: 10d
    postalCode Yes String none The postal code of the address
    city Yes String none The city of the address
    country Yes String none The country of the address

    Verifications

    Some of the verifications will affect each other. In that case, the couriers will check the strictest union of the requirements to make sure nothing is delivered to the wrong person.

    Parameter Required Type Default Description
    leaveAtDoorstep Yes Boolean none Can the courier leave the package at the doorstep if no one is at home?
    requireSignature Yes Boolean none Should the recipient sign for the package?
    idCheck Yes Boolean none Should the courier check the real identity of the recipient?
    onlyToRecipient Yes Boolean none Should the courier only deliver to the named recipient? This option implies an ID check.
    minimumAgeCheck       No       Integer                           none           Should the courier verify the age of the recipient is equal to or above this value? Package will not be delivered if recipient is younger than the age provided.

    Window

    Parameter Required Type Default Description
    start Yes DateTime none The start of the window
    end Yes DateTime none The end of the window
    token No String none The token from the availability response. Only used when placing an order.

    Parcel

    Parameter Required Type Default Description
    description Yes String none Description of the parcel and contents
    widthCm Yes Int none The width of the parcel in cm
    heightCm Yes Int none The height of the parcel in cm
    depthCm Yes Int none The depth of the parcel in cm
    weightGrams Yes Int none The weight of the package in grams
    parcelShipmentIdentifier No Digits[5-20] none The shipping identifier for the package. This is usually the number for the bar code.

    Response

    Parameter Type Description
    orderId String The id of the created order
    _links OrderResponseLinks Links for this resource.
    Parameter Type Description
    self HrefLink Link to the created order.
    labelInfo HrefLink Link to information about the labels for this order. WARNING: The contents from this URL should not be stored. The addresses have limited existense because of security concerns.
    status HrefLink Link to fetch the status of the order. Returns a Order status on a GET request.
    userInformation HrefLink Address of a wep page that displays the status of the order. This link is intended for the use of the end user and is sensitive as it also gives access to modify some elements of the order.

    Order status

    Parameter Type Description
    orderId String The id of the order.
    orderStatus String Examples: [received, delivered, cancelled] The status of the order. This list is non exhaustive so please take care to display/handle any new statuses that is introduced.
    pickupDate Date The date when the order parcels will be picked up by Porterbuddy. Depending on the delivery area, the parcels may be picked up one or more days before the delivery date.
    statusUpdatedAt DateTime The timestamp of the last order status change, as ISO timestamp with time zone.
    Parameter Type Description
    href String Link for the given role.

    Update shipment information

    This update is supposed to be used whenever you need to update the packages and shipment information after placing the order. Note that the packages list needs to be complete, so any content here removes the information from the previous order.

    PUT https://api.porterbuddy.com/order/<orderId>/update-shipment-details

    Example request:

    curl -X PUT \
      https://api.porterbuddy-test.com/order/<orderId>/update-shipment-details \
      -H 'x-api-key: <your_api_key>' \
      -H 'Content-Type: application/json' \
      -H 'Idempotency-Key: <your idempotency key>' \
      -d '{
            "parcels" : [
                {
                    "description": "Shoes",
                    "widthCm": 1,
                    "heightCm": 40,
                    "depthCm": 1,
                    "weightGrams": 2000,
                    "parcelShipmentIdentifier": "12345"
                }
            ],
            "shipmentIdentifier": "12345"
        }'
    

    Example response:

    {
      "_links": {
        "self": {
            "href": "https://api.porterbuddy-test.com/order/3520"
        },
        "labelInfo": {
            "href": "https://api.porterbuddy-test.com/order/3520/label"
        }
      }
    }
    

    Arguments

    Parameter Required Type Default Description
    parcels Yes List<Parcel> none Information about the parcels.
    shipmentIdentifier No Digits[5-20] none Shipping identifier.

    Response

    Parameter Type Description
    _links OrderResponseLinks Links for this resource.

    Confirmed Parcel Scan

    Note: We provide a solution to scan outgoing parcels on our partner portal. This endpoint is only intended to be used when integrating scanning of outgoing parcels into an own solution.

    This endpoint confirms that the parcels with the specified parcel shipment identifiers belonging to the specified order have been scanned and are confirmed to be sent. The list of parcel shipment identifiers is matched agains the parcel shipment identifiers specified in the parcel data of the order. In case unknown shipment identifiers are specified, the response contains a list of all unknown identifiers, and the HTTP Response code is 422.

    PUT https://api.porterbuddy.com/order/<orderId>/confirmed-scan

    Example Request

      https://api.porterbuddy-test.com/order/<orderId>/confirmed-scan \
      -H 'x-api-key: <your_api_key>' \
      -H 'Content-Type: application/json' \
      -H 'Idempotency-Key: <your idempotency key>' \
      -d '{
             "parcelShipmentIds": ["12345", "67890"]
          }
    

    Example Response

      {
        "unknownIds": []
      }
    

    Arguments

    Parameter Required Type Default Description
    parcelShipmentIds Yes List<String> none parcel shipment identifiers to confirm to have been scanned

    Errors

    Http errors

    Http response code Reason
    400 Invalid data The request did not pass correctly formatted JSON
    401 Unauthenticated Invalid or missing API key
    403 Forbidden Your api key is invalid or the x-api-key header is missing
    422 Invalid schema The JSON could not be parsed with valid structure and values
    500 Server error Unknown server error :(