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, use your integration Slack channel with Porterbuddy, or get in touch at integration@instabee.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 and already have a partner account in the test environment with Porterbuddy, the API key can be found in the profile section of the partner portal on https://retailers.porterbuddy-test.com/profile. If you don't have a Porterbuddy test account yet, please checkout https://porterbuddy.com/business, or you can send a request to integration@instabee.com to receive a test account invitation.

    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. Registering a user account is done by an invitation system, so please checkout https://porterbuddy.com/business for further details. After the account and user login have been created, the API key can be found at https://retailers.porterbuddy.com/profile.

    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": "2025-02-13T10:00+01:00", "end": "2025-02-13T18:00+01:00"},
                {"start": "2025-02-14T10:00+01:00", "end": "2025-02-14T18: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": 30,
                    "heightCm": 25,
                    "depthCm": 45,
                    "weightGrams": 2000
                }
            ],
            "items": [
                {
                    "name":"Fancy Sneakers",
                    "sku":"FANCYSNEAKER43",
                    "weightGrams":"600",
                    "widthCm":20,
                    "heightCm":10,
                    "depthCm":35,
                    "description":"Fancy sneakers (red/blue) in size 43",
                    "category":"shoes",
                    "brand":"Fancy Footwear Corp.",
                    "imageUrl":"https://awesomewebshop.com/images/5fd71d6f-b0be-4480-900f-f3d008a0bc62.png",
                    "price": {
                        "fractionalDenomination":"79900",
                        "currency":"NOK"
                    },
                    "barCode": {
                        "value":"123-456-789",
                        "type":"CODE128"
                    }
                },
                {
                    "name":"Heavy Boots",
                    "sku":"HEAVYBOOTS48",
                    "weightGrams":"1400",
                    "widthCm":30,
                    "heightCm":12,
                    "depthCm":45,
                    "description":"Heavy military boots, size 48",
                    "category":"shoes",
                    "brand":"Heavy Industries Inc.",
                    "imageUrl":"https://awesomewebshop.com/images/613c37e8-64be-4483-a216-9fb1b7f7e848.png",
                    "price": {
                        "fractionalDenomination":"134900",
                        "currency":"NOK"
                    },
                    "barCode": {
                        "value":"999-888-765",
                        "type":"CODE128"
                    }
                }
            ]
        }'
    

    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": [
        {
          "product": "delivery",
          "start": "2025-02-13T17:30:00+01:00",
          "end": "2025-02-13T19:30:00+01:00",
          "price": {
            "fractionalDenomination": 14900,
            "currency": "NOK"
          },
          "expiresAt": "2025-02-13T13:00:13+01:00",
          "token": "20hRsgz8AovrLjeOldJ2Wg==:yhr85il4/swdgiEP/DG2wg==:2hBoFcmyTNLp/CTfX3sTGslOJr9sXAMxHggqq/h6tGmUuCEB2Vfy8uyNIWfg3qf6d7nj84Aj2sbwMLK2hETe14L4qgnlZHVSkBcktYPc6VCp9vEZhXErpQS3HoSyRU+mVcF2SNGP4s5TI5x7S6oq4Q==",
          "consolidated": false
        },
        {
          "product": "delivery",
          "start": "2025-02-13T19:30:00+01:00",
          "end": "2025-02-13T21:30:00+01:00",
          "price": {
            "fractionalDenomination": 14900,
            "currency": "NOK"
          },
          "expiresAt": "2025-02-13T13:00:11+01:00",
          "token": "lDQ+BXxkKR9qHwv5naf6CQ==:zpR8F/PUK3YlhUkVspoQ/w==:eV5fTEQmv/6We+KaK32ji31FHHHKaG4/GFQO8s/BX9dLKQ4QlV6gLZYtXOCQU+WfbYe+x9pJOfdjaXRfC2M4oNq+bHtNHSQKY7rfjAV3IoG2DSqvT9a+z4Lp8yuFOvonEUlzWlEiT2inTcnju+JlYQ==",
          "consolidated": false
        },
        {
          "product": "delivery",
          "start": "2025-02-14T17:30:00+01:00",
          "end": "2025-02-14T19:30:00+01:00",
          "price": {
            "fractionalDenomination": 14900,
            "currency": "NOK"
          },
          "expiresAt": "2025-02-14T13:00:27+01:00",
          "token": "SW23FPWVYkyV+xJuFfJ76w==:wZl92j141aX8vBtU/bzgtQ==:kBZeBgu+JoYMaasgk+Y+F4Bsd6ntn3Q8hkbGX9/ysfnppPTmqe24ZZeBdtDwh2364DMUhc+hpyK2Aau8jW7FC/gl4E3Q84j+7OnX3CNYuRzoNlYsXI749XGr86YbVU6wt8olw8pNkkLsyF17oNDA3g==",
          "consolidated": false
        },
        {
          "product": "delivery",
          "start": "2025-02-14T19:30:00+01:00",
          "end": "2025-02-14T21:30:00+01:00",
          "price": {
            "fractionalDenomination": 14900,
            "currency": "NOK"
          },
          "expiresAt": "2025-02-14T13:00:04+01:00",
          "token": "Kj1q+VlVFG4LX3ZAwbMPPg==:t6BkqFpGFzVnpqoTqEyKgA==:GGrsm1gUTetg8ux9sTs0/+X7mQiG/9a4y67BZoXPRjB3g8F+OK4NVyaYZAdIsLcdbO36jNta8hEyyCDxVee2qi7+95RJXBP/7wuH4Ik/S2/fq+8gHBQhISm0ba9TyO4ujytN5eAlXmoZgSQSXFG2tg==",
          "consolidated": false
        }
      ],
      "flags": ["CONSOLIDATION_ENABLED"]
    }
    

    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 No List<Window> none The windows when the package is available for pick-up. Specifying this allows for fine-grained control of the number of delivery windows returned, or the earliest possible delivery option, e.g. in case of preorders. If not set, pickup windows for 7 days including the current day will be generated on the backend side. 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 ] The name of the product needed. Currently, the products "delivery" and "large" are available. The applicable products will be influenced by the destination address and the specified parcels or items, so the returned delivery window list may not contain windows for all specified products. Each window has a 'product' attribute which signals which product this is for.
    parcels (*) 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.
    items (*) List<Item> none A list of items you want to transport. Will be used to determine size and weight if no parcels are specified.

    (*) At least one of the properties "items" or "parcels" must be specified for a valid request. If only items are specified, each item must have the "weightGrams" property specified as >= 0.

    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. Note: For historic reasons, the origin address is being replaced with the address of our hub that handles the last-mile delivery. This behaviour can safely be ignored.
    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.
    flags List A list of flags indicating if certain features are enabled in the shop configuration. Mainly used for our own checkout widgets. This property will be omitted if the list would be empty.

    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 "large"
    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, may be omitted if anonymous consolidation is used.
    end DateTime The end of the window, may be omitted if anonymous consolidation is used.
    product String The product type this window is for. Example: "delivery" or "large""
    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

    Testing hints

    The test environment on api.porterbuddy-test.com is used for both testing partner integrations and for internal testing within Porterbuddy. For this reason, short downtimes can occur, and features might behave unexpectedly for short periods of time. For short-term answers, best practice is to establish an integration slack channel with Porterbuddy.

    ⚠ The test environment is configured to send out emails to specified sender and recipient email addresses. To avoid confusion, do not use email addresses of real customers, instead, rather use your own email address if you want to receive tracking links, or a non-existing one. The test environment does not send out SMS, so any phone number can be specified without consequences. ⚠

    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"
            },
            "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": "2025-02-13T17:30:00+01:00",
                    "end": "2025-02-13T19:30:00+01:00",
                    "token": "20hRsgz8AovrLjeOldJ2Wg==:yhr85il4/swdgiEP/DG2wg==:2hBoFcmyTNLp/CTfX3sTGslOJr9sXAMxHggqq/h6tGmUuCEB2Vfy8uyNIWfg3qf6d7nj84Aj2sbwMLK2hETe14L4qgnlZHVSkBcktYPc6VCp9vEZhXErpQS3HoSyRU+mVcF2SNGP4s5TI5x7S6oq4Q=="
                },
                "verifications": {
                    "minimumAgeCheck": null,
                    "requireSignature": false,
                    "deliveryVerification":"CONTACTLESS",
                    "confirmCustomerReceipt": false
                }
            },
            "parcels" : [
                {
                    "description": "Shoes",
                    "widthCm": 30,
                    "heightCm": 25,
                    "depthCm": 45,
                    "weightGrams": 2000,
                    "parcelShipmentIdentifier": "12345",
                    "constraints": {
                        "temperature": {
                            "maximumCelsius": 25.0,
                            "minimumCelsius": 10.0
                        }
                    }
                }
            ],
            "items": [
                {
                    "name":"Fancy Sneakers",
                    "sku":"FANCYSNEAKER43",
                    "weightGrams":"600",
                    "widthCm":20,
                    "heightCm":10,
                    "depthCm":35,
                    "description":"Fancy sneakers (red/blue) in size 43",
                    "category":"shoes",
                    "brand":"Fancy Footwear Corp.",
                    "imageUrl":"https://awesomewebshop.com/images/5fd71d6f-b0be-4480-900f-f3d008a0bc62.png",
                    "price": {
                        "fractionalDenomination":"79900",
                        "currency":"NOK"
                    },
                    "barCode": {
                        "value":"123-456-789",
                        "type":"CODE128"
                    }
                },
                {
                    "name":"Heavy Boots",
                    "sku":"HEAVYBOOTS48",
                    "weightGrams":"1400",
                    "widthCm":30,
                    "heightCm":12,
                    "depthCm":45,
                    "description":"Heavy military boots, size 48",
                    "category":"shoes",
                    "brand":"Heavy Industries Inc.",
                    "imageUrl":"https://awesomewebshop.com/images/613c37e8-64be-4483-a216-9fb1b7f7e848.png",
                    "price": {
                        "fractionalDenomination":"134900",
                        "currency":"NOK"
                    },
                    "barCode": {
                        "value":"999-888-765",
                        "type":"CODE128"
                    }
                }
            ],
            "product": "delivery",
            "courierInstructions": "Test",
            "orderReference": "NJ12345"
        }'
    

    Example response:

    {
      "orderId": "3520",
      "pickupDate": "2025-02-13",
      "pickupTime": "2025-02-13T15:00:00+02:00",
      "_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 (*) List<Parcel> none Information about the parcels.
    product Yes String none The product associated with the window chosen. Should be taken from the delivery window's properties.
    orderReference No String none Your internal order reference.
    tmsReference No String none Your internal tms 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.
    items (*) List<Item> none Information about the items (goods) in the order.
    statusWebhookUrl No URL none Url of a webhook that gets called when the pickup date or order status changes. See Order Status Webhook

    (*) At least one of the properties "items" or "parcels" must be specified for a valid request. If only items are specified, each item must have the "weightGrams" property specified as >= 0.

    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 No List<Window> none The available windows to pick up the package, only relevant if destination.bestAvailableWindow is set to true. If not specified in the best available case, the backend will try to chose a delivery window within the next 10 days. If a delivery window or consolidated window is specified, this property will be ignored.

    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. If a delivery window or consolidated delivery window is specified, this property is ignored.
    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 or consolidatedWindow is used.
    consolidatedWindow No ConsolidatedWindow none if the user chose the consolidated delivery window, this field needs to be filled with the consolidated window data from the availability request.
    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 deprecated verification properties 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. The deprecated properties are only evaluated if deliveryVerification is not provided.

    Parameter Required Type Default Description
    leaveAtDoorstep No Boolean false Deprecated, use deliveryVerifications property instead
    requireSignature No Boolean null Should the recipient sign for the package? Note: Taking signatures is currently replaced with confirmation via recipient pincode.
    idCheck No Boolean null Deprecated, use deliveryVerifications property instead. Former usage: should the courier check the real identity of the recipient?
    onlyToRecipient No Boolean null Deprecated, use deliveryVerifications property instead. Former usage: should the courier only deliver to the named recipient? This option implies an ID check.
    minimumAgeCheck No Integer null 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.
    confirmCustomerReceipt No Boolean false Should the recipient be asked to confirm that the parcel is received and taken inside (for contactless delivery)?
    deliveryVerification No DeliveryVerification CONTACTLESS* Enum to select the delivery verification mode.

    * If requireSignature is set to true or minimumAgeCheck has a positive value, the default value for deliveryVerification is REQUIRE_PIN.

    DeliveryVerification

    Value Description
    CONTACTLESS Delivery is performed contactless by placing parcels on the doorstep. Customers can choose to switch to personal delivery on their own accounts.
    ALLOW_CONTACTLESS Delivery is performed in person with pin verification. Customers can change to contactless delivery on their own accounts and responsibility
    REQUIRE_PIN Delivery is performed in person with pin verification. Customers are not allowed to change to contactless delivery
    REQUIRE_ID Delivery is performed in person with id verification. The recipient is only required to show an id, but does not need to be the same person as the recipient named in order data.
    ONLY_TO_RECIPIENT Delivery is performed in person with id verification. The recipient must be the same person as the named recipient in the order data.

    Enum for the way the delivery is verified. In case of a consolidated delivery, the strictest delivery verification is performed for the whole delivery.

    Window

    Parameter Required Type Default Description
    start (*) DateTime none The start of the window
    end (*) DateTime none The end of the window
    token (*) String none The token from the availability response. If only a token is specified, the start and end times will be extracted from that token.

    (*) Either start and end or token must be present for the request to be handled. If all properties are null, the request will be rejected. If start and end time as well as token are provided, a check will be performed to make sure token and times match up.

    ConsolidatedWindow

    Parameter Required Type Default Description
    token Yes 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 No Int none The width of the parcel in cm
    heightCm No Int none The height of the parcel in cm
    depthCm No 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.
    constraints No* ParcelConstraints none Constraints for parcel delivery.
    * Some api calls like /update-shipment-details will override the existing parcel data, including constraints. Make sure not to change the constraints after the labels for the order are printed.

    ParcelConstraints

    Parameter Required Type Default Description
    temperature no TemperatureConstraints none Temperature constraints for the parcel.

    TemperatureConstraints

    Parameter Required Type Default Description
    maximumCelsius yes double none maximum storage temperature in degrees Celsius
    minimumCelsius yes double none minimum storage temperature in degrees Celsius

    Temperature control requirements are specified per parcel. The information can either be passed during order creation, or when updating the shipment details / adding parcels. Take care not to overwrite parcel constraints unintentionally. If the constraints are changed purposefully they should be done so as early as possible, and should not be changed after the label(s) are printed.

    Item

    Parameter Required Type Default Description
    weightGrams (*) Int none Weight of the item in grams. Required if only items and no parcels are specified in the request.
    widthCm no Int none Width of the item in cm
    heightCm no Int none Height of the item in cm
    depthCm no Int none Depth of the item in cm
    name no String none The item's name
    sku no String none SKU for the item
    price no Price none Sales price per unit of the item
    cost no Price none Cost per unit of the item
    description no String none Description of the item
    category no String none A product category for the item.
    brand no String none Brand name the item is sold under
    imageUrl no String none A URL linking to an image of the product
    barCode no BarCode none A unique barcode identifying the product
    storageTemperature no Int none Temperature the item should be stored at. Note: For reference purposes only, if items need to be handled at specific temperatures, it needs to be specified as parcel restrictions and the delivery agreement with Porterbuddy must include temperature-controlled handling.

    (*) If items are specified instead of parcels in an Availability- or OrderRequest, the weightGrams property must be specified as >= 0. It can be omitted if a list of parcels is specified in the requests additionally.

    BarCode

    Parameter Required Type Default Description
    value yes String none Value encoded in the barcode. Represented as string to support different barcode formats.
    type yes String none Barcode type, e.g. Code128, UPC, ...

    Response

    Parameter Type Description
    orderId String The id of the created order
    pickupDate Date Deprecated, use pickupTime instead! Calculated date the order needs to be picked up to be delivered on time.
    pickupTime DateTime Calculated date and time the order needs to be picked up to be delivered on time.
    _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 Deprecated, use pickupTime instead! 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.
    pickupTime DateTime Calculated date and time the order needs to be picked up to be delivered on time.
    statusUpdatedAt DateTime The timestamp of the last order status change, as ISO timestamp with time zone.
    orderReference String Order reference as specified in order request / shipment details update
    tmsReference String TMS reference as specified in order request
    Parameter Type Description
    href String Link for the given role.

    Implementation hints

    Idempotency Keys

    Requests to create orders use an idempotency key specified as header to identify duplicate requests. This is intended to prevent orders to be created twice in our system by an accidentally repeated request, e.g. in case the request was handled successfully on Porterbuddy's side, but too slow, so it would trigger a timeout on the integrator's side. Thus, the idempotency key should be chosen in a way that it corresponds to the order to be created with the request, e.g. your unique order reference, a hash value of the body data, or similar, the only requirement is that if the data is for the same order on your side, the idempotency key must be the same. If an order request is handled with an idempotency key already used on an existing order, the response returned contains the dataset for the existing order.

    Phone Number Validation

    Phone numbers are validated using libphonenumber. The validation rules applied to the national number depend on the specified country code, for that reason, a documentation of the validation rules is not provided by the libphonenumber developers. Some hints for passing validation are these: * country codes can be specified both in 00XX as well as in +XX form * it is advised to remove white space in phone numbers * length validation depends on country. For Norway, national numbers are expected to be 8 digits long. For other countries, other rules apply. * Phone numbers consisting only of zeros will fail validation.

    Update shipment details

    This update is supposed to be used whenever you need to update the packages and shipment information after placing the order. Note that the parcel list needs to be complete, including constraints, as any content here overwrites the existing information on the 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' \
      -d '{
            "parcels" : [
                {
                    "description": "Shoes",
                    "widthCm": 1,
                    "heightCm": 40,
                    "depthCm": 1,
                    "weightGrams": 2000,
                    "parcelShipmentIdentifier": "12345",
                    "constraints": {
                        "temperature": {
                            "maximumCelsius": 25.0,
                            "minimumCelsius": 10.0
                        }
                    }
                }
            ],
            "shipmentIdentifier": "12345",
            "orderReference": "order-#12345678",
            "verifications": {
                "minimumAgeCheck": null,
                "requireSignature": false,
                "deliveryVerification":"CONTACTLESS",
                "confirmCustomerReceipt": false
            }
        }'
    

    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.
    orderReference No String none Your internal order reference. If this parameter is not set, the current order reference will not be removed.
    verifications No VerificationsUpdate none Update for the verifications to be performed by the courier. Only non-null properties in this object will be updated.

    VerificationsUpdate

    Parameter Required Type Default Description
    minimumAgeCheck No Integer null 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.
    requireSignature No Boolean null Should the recipient sign for the package? Note: Taking signatures is currently replaced with confirmation via recipient pincode.
    confirmCustomerReceipt No Boolean null Should the recipient be asked to confirm that the parcel is received and taken inside (for contactless delivery)?
    deliveryVerification No DeliveryVerification null Enum to select the delivery verification mode.

    Response

    Parameter Type Description
    _links OrderResponseLinks Links for this resource.

    Set parcel details

    Used to append information to a parcel. It will ignore missing keys and null values, and can thus only add or change information on a parcel. If you need to remove parcel information use /update-shipment-details. A prerequisite for using this endpoint is that the parcel has a parcelShipmentIdentifier. This can either be set at order creation, or via /update-shipment-details.

    PUT https://api.porterbuddy.com/order/<orderId>/set-parcel-details/<parcelShipmentIdentifier>

    Example request:

    curl -X PUT \
      https://api.porterbuddy.com/order/<orderId>/set-parcel-details/<parcelShipmentIdentifier> \
      -H 'x-api-key: <your_api_key>' \
      -H 'Content-Type: application/json' \
      -d '{
            "description": "Shoes",
            "widthCm": 1,
            "heightCm": 40,
            "depthCm": 1,
            "weightGrams": 2000,
            "constraints": {
                "temperature": {
                    "maximumCelsius": 25.0,
                    "minimumCelsius": 10.0
                }
            }
        }'
    

    Arguments

    Parameter Required Type Default Description
    description No String none Description of the parcel and contents
    widthCm No Int none The width of the parcel in cm
    heightCm No Int none The height of the parcel in cm
    depthCm No Int none The depth of the parcel in cm
    weightGrams No Int none The weight of the package in grams
    constraints No ParcelConstraints none Constraints for parcel delivery.
    * Make sure not to change the constraints after the labels for the order are printed.

    Response

    200 OK if the request was successful.

    404 Not Found if no parcel is found for combination of orderId and parcelShipmentIdentifier.

    Fetch labels

    The order creation and update shipment information endpoints contain a URL to fetch label information from. This endpoint can be called to receive URLs for downloading label files.

    GET https://api.porterbuddy-test.com/order/<orderId>/label

    Example Request

    curl -X GET \
      https://api.porterbuddy-test.com/order/3520/label \
      -H 'x-api-key: <your_api_key>' \
      -H 'Accept: application/json'
    

    Example response

    {
      "shipmentLabelUrl": "https://api.porterbuddy-test.com/order/3520/label/4ZvwE4kloM3vyQN4tuO5UC",
      "packages": [{
        "labelUrl": "https://api.porterbuddy-test.com/order/3520/label/4ZvwE4kloM3vyQN4tuO5UC/5f6e4f5f-7ce4-4568-b7d1-5fc8c8c6af10",
        "parcelShipmentIdentifier": "12345"
      }]
    }
    

    Response

    Parameter Type Description
    shipmentLabelUrl URL Label document containing all labels for the order, one for each specified parcel
    packages PackageLabelInfo List of label urls for each parcel

    PackageLabelInfo

    Parameter Type Description
    labelUrl URL Label document for the parcel. This document contains exactly 1 label.
    parcelShipmentIdentifier String Shipment Identifier for the individual parcel.

    The label documents can be retrieved by fetching the document from the URLs in this response. The label document endpoints do not require authentication, but contain a unique (per order) token as part of the URL to ensure they can only be used by authorized parties.

    Label File Format

    Labels can be retrieved in various format. The default format is PDF, and we recommend using PDFs for the labels due to the superior behavior when printing. Other label formats can be requested by setting the Accept header of the request to fetch the label content.

    Label Size

    The default size for Porterbuddy labels is 102mm*192mm (width*height). Labels must be printed in 100% size. If smaller labels are necessary, Porterbuddy offers the following options:

    1. Porterbuddy can set a default smaller label size of 102mm*102mm to be returned.
    2. The label size for each label can be influenced by adding a query parameter size to the request to fetch the label document. size=REGULAR will force the label(s) to be generated in the regular format of 102*192, size=SMALL will return the 102*102 sized version. Calls to the label URLs without the query parameter will return the default size as configured.

    Fetch order status

    The order status can be retrieved using the URL returned from the Create Order call. The order status contains the pickup date, which is updated in case the recipient changes the delivery day, so it should be fetched regularly.

    GET https://api.porterbuddy.com/order/<orderId>/status

    Example Request

    curl -X GET \
      https://api.porterbuddy-test.com/order/<orderId>/status \
      -H 'x-api-key: <your_api_key>' \
      -H 'Accept: application/json'
    

    Example Response

    {
      "orderId": "3520",
      "orderStatus": "ready",
      "pickupDate": "2025-02-13",
      "pickupTime": "2025-02-13T15:00:00+02:00",
      "statusUpdatedAt": "2021-03-25T10:30:35.742857Z",
      "orderReference": "order-#12345678",
      "tmsReference": "order-#12345678"
    }
    

    Fetch order status with order reference

    The order status can also be retrieved using order reference. The order status contains the pickup date, which is updated in case the recipient changes the delivery day, so it should be fetched regularly.

    GET https://api.porterbuddy.com/order/order-reference/<order-reference>/status

    Example Request

    curl -X GET \
      https://api.porterbuddy-test.com/order/order-reference/<order-reference>/status \
      -H 'x-api-key: <your_api_key>' \
      -H 'Accept: application/json'
    

    Example Response

    {
      "orderId": "3520",
      "orderStatus": "ready",
      "pickupDate": "2025-02-13",
      "pickupTime": "2025-02-13T15:00:00+02:00",
      "statusUpdatedAt": "2021-03-25T10:30:35.742857Z",
      "orderReference": "order-#12345678",
      "tmsReference": "order-#12345678"
    }
    

    Fetch order status with TMS reference

    The order status can also be retrieved using TMS reference. The order status contains the pickup date, which is updated in case the recipient changes the delivery day, so it should be fetched regularly.

    GET https://api.porterbuddy.com/order/tms-reference/<tms-reference>/status

    Example Request

    curl -X GET \
      https://api.porterbuddy-test.com/order/tms-reference/<tms-reference>/status \
      -H 'x-api-key: <your_api_key>' \
      -H 'Accept: application/json'
    

    Example Response

    {
      "orderId": "3520",
      "orderStatus": "ready",
      "pickupDate": "2025-02-13",
      "pickupTime": "2025-02-13T15:00:00+02:00",
      "statusUpdatedAt": "2021-03-25T10:30:35.742857Z",
      "orderReference": "order-#12345678",
      "tmsReference": "order-#12345678"
    }
    

    Response

    see Order Status

    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' \
      -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

    Place a consolidated 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"
            },
            "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",
                "consolidatedWindow":{
                    "token": "20hRsgz8AovrLjeOldJ2Wg==:yhr85il4/swdgiEP/DG2wg==:2hBoFcmyTNLp/CTfX3sTGslOJr9sXAMxHggqq/h6tGmUuCEB2Vfy8uyNIWfg3qf6d7nj84Aj2sbwMLK2hETe14L4qgnlZHVSkBcktYPc6VCp9vEZhXErpQS3HoSyRU+mVcF2SNGP4s5TI5x7S6oq4Q=="
                },
                "verifications": {
                    "minimumAgeCheck": null,
                    "requireSignature": false,
                    "deliveryVerification":"CONTACTLESS",
                    "confirmCustomerReceipt": false
                }
            },
            "parcels" : [
                {
                    "description": "Shoes",
                    "widthCm": 1,
                    "heightCm": 40,
                    "depthCm": 1,
                    "weightGrams": 2000,
                    "parcelShipmentIdentifier": "12345"
                }
            ],
            "product": "delivery",
            "courierInstructions": "Test",
            "orderReference": "NJ12345"
        }'
    

    Consolidated orders (the "Samlevert" product) are created via the same request as regular orders, by using the token from the consolidated window returned in the availability call to fill the data for the "consolidatedWindow" property in the create order request. This should be done if the customer has chosen the consolidated delivery option in the checkout. The data model for request and response is explained in the section Place Order, so this section only contains the different example request, the response has the same structure as for the non-consolidated case.

    Note: The example request will not work as is, as to create an actually consolidated order, several conditions have to be met:

    If the consolidated window token has expired or is invalid, the order is created using the "best-available" approach.

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

    Fetching Order Data

    Data for an existing order can be fetched from the endpoint /order/<orderId>/self. This endpoint will return a basic data set for placed orders that also includes links to the label endpoint and customer tracking page. The API for this endpoint can be considered stable, so it's preferable to use this endpoint instead of /order/<orderId> to retrieve order information.

    Example Request

     curl -X GET \
      https://api.porterbuddy-test.com/order/<orderId>/self \
      -H 'x-api-key: <your_api_key>' \
      -H 'Accept: application/json'
    

    Example Response

    {
      "id": "13218",
      "created": "2021-05-31T07:13:41.525648Z",
      "deliverFrom": "2021-06-10T10:00:00Z",
      "deliverUntil": "2021-06-10T14:00:00Z",
      "pickupAddress": {
        "streetName": "Keysers Gate",
        "streetNumber": "3",
        "postalCode": "0165",
        "city": "Oslo",
        "country": "Norway",
        "location": {
          "latitude": 59.91698083192638,
          "longitude": 10.743384544175152
        },
        "addressType": "NORMAL",
        "addressValidity": "VALID",
        "fullAddressString": "Keysers Gate 3, 0165 Oslo, Norway"
      },
      "destinationAddress": {
        "streetName": "Høyenhallveien",
        "streetNumber": "25",
        "postalCode": "0678",
        "city": "Oslo",
        "country": "Norway",
        "location": {
          "latitude": 59.90325905025783,
          "longitude": 10.81379348938312
        },
        "addressType": "NORMAL",
        "addressValidity": "VALID",
        "fullAddressString": "Høyenhallveien 25, 0678 Oslo, Norway"
      },
      "pickupRegion": "OSLO",
      "destinationRegion": "OSLO",
      "recipientName": "Roger Olsen (Recipient)",
      "recipientPhoneNumber": "65789832",
      "recipientPhoneCountryCode": "+47",
      "recipientEmail": "testemail+recipient_ves4ab9qjc@porterbuddy.com",
      "pickupName": "Nils Johansen (Sender)",
      "pickupPhoneNumber": "65127865",
      "pickupPhoneCountryCode": "+47",
      "pickupEmail": "testemail+sender@porterbuddy.com",
      "pickupPin": "02766",
      "deliveryType": "SCHEDULED",
      "status": "ready",
      "xxl": false,
      "token": "1VgOBLIHOQSNNxaiS6AaVt",
      "parcels": [{
        "description": "Parcel description",
        "widthCm": 1,
        "heightCm": 40,
        "depthCm": 1,
        "weightGrams": 2000,
        "volumeCm3": null,
        "parcelShipmentIdentifier": null,
        "parcelId": "49883d8a-4319-4f7d-a081-132e0a7d1233",
        "locationToken": null,
        "originAddress": null,
        "constraints": null,
        "volume": 40
      }],
      "verifications": {
        "minimumAgeCheck": 16,
        "leaveAtDoorstep": false,
        "idCheck": true,
        "requireSignature": false,
        "onlyToRecipient": true,
        "deliveryVerification":"REQUIRE_PIN",
        "confirmCustomerReceipt": false
      },
      "orderReference": "c46e068c-a3bb-4429-ac12-f81ee3ce9e86",
      "tmsReference": "511bd245-8204-4330-98a3-5e58be8ba1eb",
      "statusUpdatedAt": "2021-05-31T07:13:41.525648Z",
      "pickupDate": "2021-06-10",
      "pickedAt": null,
      "scannedAtPartner": null,
      "scannedAtHub": null,
      "deliveredAt": null,
      "links": {
        "labelInfo": "https://api.porterbuddy.com/order/13218/label",
        "userInformation": "https://tracking.porterbuddy.com/74nBxcSLzQI0FIjJuZZHRQ"
      }
    }
    

    Response

    Parameter Type Description
    id String The Porterbuddy order id
    created DateTime Order creation data
    deliverFrom DateTime Start of the delivery window
    deliverUntil DateTime End of the delivery window
    pickupAddress Resolved Address Specified origin address for the order, usually the retailer's warehouse address
    destinationAddress Resolved Address Destination address for the order (recipient address)
    pickupRegion String Region the order will be picked up (e.g. "OSLO", "BERGEN", ...). The list is non-exhaustive, so make sure to handle new values properly.
    destinationRegion String Region the order will be delivered to
    recipientName String Name of the recipient
    recipientPhoneNumber String Recipient's phone number
    recipientPhoneCountryCode String Country code for the recipient's phone number
    recipientEmail String The recipient's email address
    pickupName String Pickup name (the sender name specified in the order create request and printed on the label)
    pickupPhoneNumber String Sender's phone number
    pickupPhoneCountryCode String Country code for the sender's phone number
    pickupEmail String Sender email as specified in the order create request - used for sender receipts if enabled
    pickupPin String 5-digit pin code from the parcel label
    deliveryType String Type of the delivery - currently always "SCHEDULED"
    status String Current order status, e.g. [received, delivered, cancelled]. The list is non-exhaustive, so make sure to handle new values properly.
    xxl Boolean Indicates that the order is oversized/overweight
    token String Order token
    parcels List<Parcel> Current parcel specification
    verifications Verifications Verifications to perform on delivery
    orderReference String External order reference as specified
    tmsReference String External tms reference as specified
    statusUpdatedAt DateTime Timestamp of the last status update
    pickupDate Date Calculated pickup date, based on the specified delivery date
    pickedAt DateTime Timestamp the order was picked up by the courier
    scannedAtPartner DateTime Timestamp the order was scanned by the partner (retailer)
    scannedAtHub DateTime Timestamp of the first time the order was scanned at a Porterbuddy hub
    deliveredAt DateTime Timestamp the order was delivered at
    links OrderInfoLinks Links for customer tracking page and label endpoint
    Parameter Type Description
    labelInfo URL Link to the label info endpoint
    userInformation URL Link to the recipient tracking page

    Order Status Webhook

    Example Order Request

    {
          "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":"2025-02-13T10:00+02:00", "end":"2025-02-13T20: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": "2025-02-13T17:30:00+01:00",
              "end": "2025-02-13T19:30:00+01:00",
              "token": "20hRsgz8AovrLjeOldJ2Wg==:yhr85il4/swdgiEP/DG2wg==:2hBoFcmyTNLp/CTfX3sTGslOJr9sXAMxHggqq/h6tGmUuCEB2Vfy8uyNIWfg3qf6d7nj84Aj2sbwMLK2hETe14L4qgnlZHVSkBcktYPc6VCp9vEZhXErpQS3HoSyRU+mVcF2SNGP4s5TI5x7S6oq4Q=="
            },
            "verifications": {
              "minimumAgeCheck": null,
              "requireSignature": false,
              "deliveryVerification":"CONTACTLESS",
              "confirmCustomerReceipt": false
            }
          },
          "parcels" : [
            {
              "description": "Shoes",
              "widthCm": 20,
              "heightCm": 10,
              "depthCm": 35,
              "weightGrams": 600,
              "parcelShipmentIdentifier": "12345",
              "constraints": {
                "temperature": {
                  "maximumCelsius": 25.0,
                  "minimumCelsius": 10.0
                }
              }
            }
          ],
          "items": [
            {
              "name":"Fancy Sneakers",
              "sku":"FANCYSNEAKER43",
              "weightGrams":"600",
              "widthCm":20,
              "heightCm":10,
              "depthCm":35,
              "description":"Fancy sneakers (red/blue) in size 43",
              "category":"shoes",
              "brand":"Fancy Footwear Corp.",
              "imageUrl":"https://awesomewebshop.com/images/5fd71d6f-b0be-4480-900f-f3d008a0bc62.png",
              "price": {
                "fractionalDenomination":"79900",
                "currency":"NOK"
              },
              "barCode": {
                "value":"123-456-789",
                "type":"CODE128"
              }
            }
          ],
          "product": "delivery",
          "courierInstructions": "Test",
          "orderReference": "order-12345",
          "tmsReference": "order-12345",
          "statusWebhookUrl": "https://api.myshopbackend.com/statusUpdated"
    }
    

    To receive notifications when the order status or pickup date changes, a webhook URL can be specified in the order request as property statusWebhookUrl. This URL gets called with HTTP POST every time the status or pickup date changes, and contains the same body as the Order Status Endpoint. The target endpoint must be reachable from the internet without authentication and respond within 10 seconds. If a status outside the [200..299] range is returned, or the endpoint is unreachable, the call will be retried 2 times with a rising interval. The response body will be ignored by our backend.

    Webhook call body

    Example Body

    {
      "orderId": "394326",
      "orderStatus": "canceled",
      "pickupDate": "2025-02-13",
      "pickupTime": "2025-02-13T15:00:00+02:00",
      "statusUpdatedAt": "2021-06-08T12:16:40.32538Z",
      "orderReference": "order-12345",
      "tmsReference": "order-12345"
    }
    

    See Order Status

    Verifying Webhook Authenticity

    To verify that a call to the status webhook was originated by Porterbuddy, we add a header x-porterbuddy-hmac-SHA256 to the webhook calls. This header contains a base64-encoded HMAC Digest of the call body, using the sender's API key as encryption secret. Authenticity can be verified by calculating the HMAC digest of the request body on the recipient side, and comparing it to the header value.

    Confirm order

    This endpoint is a workaround for retailers using Klarna checkout, with the shipping assistant and Vipps payment. Confirming an order with this endpoint essentially tells Porterbuddy the order is considered paid for, and should be processed. The earlier this call is made the better, as it avoids delayed cancellations. In addition, it will trigger the sending of a confirmation and tracking link to the end user, in the cases where the order was not confirmed through the Klarna API (i.e Vipps payments).

    PUT https://api.porterbuddy.com/order/<orderId>/confirm

    Returns an empty 200 OK if the call succeeded.

    curl -X PUT \
      https://api.porterbuddy-test.com/order/<orderId>/confirm \
      -H 'x-api-key: <your_api_key>'
    

    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 :(