Delivery options

Technical integration guide for the @myparcel/delivery-options widget (v6). Drop it into your checkout, catch the selection event and pass the payload through to /shipments.

SandboxTry the widget without installing anythingTweak any config key in real time and watch the UI and event payload react instantly.
Open the sandbox

In short

The Delivery Options widget shows your checkout which delivery options and pickup points are available for the entered address. On selection your frontend receives a CustomEvent with carrier, date, delivery type, package type and shipment options — pass it through 1-to-1 to POST /shipments. Vue 3 under the hood, but it also works standalone via <script> tags. Source: github.com/myparcelnl/delivery-options ↗.

Looking for…

GoalSection
Install via CDN or npm1 · Install
Vue 3 or vanilla JS integration3 · Initialise
Catch selection and errors4 · Events
Available carriers / options5 · Carriers and options
Configuration reference6 · Configuration reference
Cutoff times and drop-off days7 · Drop-off days and cutoff
Pickup points (list/map)8 · Pickup points
Send the selection to /shipments9 · Handling the selection
Migrate from v5 to v610 · Migrate v5 → v6

Status of this page

The old version at developer.myparcel.nl/documentation/60.delivery-options.html ↗ is outdated. This page is written against @myparcel/delivery-options v6.26.1.

1 · Install

Option A — CDN (fastest, no build step)

Two variants: either you load Vue yourself, or you use the bundle that includes Vue.

<!-- Variant 1: load Vue yourself -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.4"></script>
<script src="https://cdn.jsdelivr.net/npm/@myparcel/delivery-options@6/dist/myparcel.lib.js"></script>
<link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@myparcel/delivery-options@6/dist/style.css" />

<!-- Variant 2: bundle including Vue -->
<script src="https://cdn.jsdelivr.net/npm/@myparcel/delivery-options@6/dist/myparcel.js"></script>
<link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@myparcel/delivery-options@6/dist/style.css" />

Which variant should I pick?

Does your shop already bundle Vue 3? Use myparcel.lib.js (single Vue instance, smaller bundle). No Vue in your stack? Use myparcel.js — then you only need to load the stylesheet alongside it.

Option B — npm

npm install @myparcel/delivery-options
import '@myparcel/delivery-options/dist/myparcel.js';
import '@myparcel/delivery-options/dist/style.css';

For Vue 3 projects that import the component directly, use the /lib export (see §3 · Vue 3).

Requirements

Version
BrowsersEvergreen (latest 2 versions of Chrome, Firefox, Safari, Edge)
Vue (only with myparcel.lib.js)^3.4
Node (build)^18 || ^20
Stylesheetdist/style.cssmust be loaded separately, otherwise the widget renders unstyled

2 · Architecture at a glance

┌──────────────┐    update event        ┌──────────────┐
│  your        │ ─────────────────────► │  Delivery    │
│  checkout    │   (CustomEvent)        │  Options     │
└──────────────┘                        │  widget      │
       ▲       ◄───────────────────────  │  (Vue 3)     │
       │       updated/error event       └──────────────┘
       │                                        │
       └────────► POST /shipments  ◄────────────┘
                  (selection payload)

Three integration points:

  1. Init — give the widget a configuration (address + carrier settings) via a prop or via dispatchEvent('myparcel_update_delivery_options', { detail: config }).
  2. Selection — the widget renders inside <div id="myparcel-delivery-options">, the user picks an option, you catch myparcel_updated_delivery_options.
  3. Submit — on checkout submit you take the latest payload and forward it to /shipments (REST API or via the PHP SDK / JS SDK).

3 · Initialise

Vue 3 component

import { ref, type Ref } from 'vue';
import {
  MyParcelDeliveryOptions,
  type InputDeliveryOptionsConfiguration,
} from '@myparcel/delivery-options/lib';

const configuration: Ref<InputDeliveryOptionsConfiguration> = ref({
  address: {
    cc: 'NL',
    postalCode: '2132JE',
    number: '31',
    street: 'Antareslaan 31',
    city: 'Hoofddorp',
  },
  config: {
    platform: 'myparcel',
    carrierSettings: {
      postnl: {},
    },
  },
});
<template>
  <MyParcelDeliveryOptions :configuration="configuration" />
</template>

<style>
@import '@myparcel/delivery-options/style.css';
</style>

Mutating configuration.value re-renders the widget — useful when the address only becomes known later in the checkout flow.

Plain JavaScript / non-Vue

HTML mount point:

<div id="myparcel-delivery-options"></div>

Initialise via a CustomEvent:

const configuration = {
  selector: '#myparcel-delivery-options',
  address: {
    cc: 'NL',
    postalCode: '2132JE',
    number: '31',
    street: 'Antareslaan 31',
    city: 'Hoofddorp',
  },
  config: {
    platform: 'myparcel',
    carrierSettings: {
      postnl: {},
    },
  },
};

document.dispatchEvent(
  new CustomEvent('myparcel_update_delivery_options', { detail: configuration }),
);

window.MyParcelConfig

A one-shot init also works via window.MyParcelConfig = configuration before the widget script loads. For dynamic updates, stick to the CustomEvent route.

4 · Events

Inbound — update config

EventDetailWhen
myparcel_update_delivery_optionsInputDeliveryOptionsConfigurationInitialisation or re-render on address change.

Outbound — selection and errors

EventDetailWhen
myparcel_updated_delivery_optionsSelection payload (see below)Every time the user makes or changes a choice.
myparcel_error_delivery_options{ exception: { code, label, status, title, message } }Validation error from the API (e.g. invalid postal code).

Selection payload

{
  "carrier": "postnl",
  "date": "2026-04-10 00:00:00.000000",
  "deliveryType": "morning",
  "isPickup": false,
  "packageType": "package",
  "shipmentOptions": {
    "signature": true,
    "onlyRecipient": true
  }
}

For isPickup: true the payload also contains a pickupLocation object with locationCode, retailNetworkId, street, number, postalCode, city, cc, latitude, longitude and openingHours.

Listener

document.addEventListener('myparcel_updated_delivery_options', (event) => {
  // persist in state — e.g. Vuex/Pinia/Redux/sessionStorage
  window.__lastDeliveryChoice = event.detail;
});

document.addEventListener('myparcel_error_delivery_options', (event) => {
  // show a friendly error to the customer; log to Sentry/Datadog
  console.error(event.detail.exception);
});

Error codes (selection)

CodeStatusMeaning
3501422Street cannot be parsed — postal code is valid but address parsing fails.
3505422Postal code does not exist.
3506422Postal code outside the carrier's service area.
3508422No deliverable options for this date/day.

The full set lives in src/types/events.types.ts and the runtime validation in src/config/validateConfiguration.ts.

5 · Carriers and options

carrierSettings accepts a separate block per carrier. An empty {} means: use the account defaults from the MyParcel backoffice.

KeyCarrierMarkets
postnlPostNLNL, BE
dhlforyouDHL For YouNL
dhlparcelconnectDHL Parcel ConnectEU
dhleuroplusDHL EuroplusEU
dpdDPDNL, BE, EU
glsGLSNL, BE, EU
bpostbpostBE
upsUPS Standard / Express SaverEU/Worldwide
trunkrsTrunkrsNL (since v6.22)
config: {
  platform: 'myparcel',
  carrierSettings: {
    postnl: {
      allowMorningDelivery: true,
      allowEveningDelivery: true,
      priceMorningDelivery: 195,   // cents
      priceEveningDelivery: 195,
      allowPickupLocations: true,
    },
    dhlforyou: {
      allowEveningDelivery: true,  // since v6.25
    },
  },
},

Per carrier, only the options that the carrier and your shop contract support are shown. The widget hides unavailable combinations on its own.

6 · Configuration reference

This is how configuration is organised:

type InputDeliveryOptionsConfiguration = {
  address?: AddressInput;
  config: {
    platform: 'myparcel' | 'sendmyparcel';
    locale?: string;            // e.g. 'nl-NL', 'nl-BE', 'fr-BE'
    carrierSettings: Record<string, CarrierSetting>;
    // ...display & feature flags below
  };
  strings?: Partial<Record<StringsKey, string>>;
};

Top-level config

KeyTypeDefaultWhen
platform'myparcel' | 'sendmyparcel'Required. myparcel for NL shops, sendmyparcel for BE shops.
localestringplatform defaultUI language, e.g. nl-NL, fr-BE.
carrierSettingsobjectRequired — at least one carrier key.
currencystringplatform defaultCurrency display for surcharges.

Display settings

KeyTypeDefaultPurpose
showPricesbooleantrueShow surcharges next to options.
showPriceSurchargebooleantrueShow the price difference vs. the standard option.
showDeliveryDatebooleantrueShow "tomorrow / Thursday 12 Mar". Deprecated since v6.26.0.
pickupShowDistancebooleantrueDistance from the address for pickup points.
allowPickupLocationsViewSelectionbooleantrueToggle button between list and map view.
pickupLocationsDefaultView'list' | 'map''list'Initial view.
pickupLocationsMapTileLayerDataobjectOSM defaultCustom tile server for the map (Mapbox/MapTiler).

Delivery options (set per carrierSettings.<carrier> for finer-grained control)

KeyTypePurpose
allowDeliveryOptionsbooleanMaster switch for home delivery.
allowStandardDeliverybooleanStandard.
priceStandardDeliverynumberCents.
allowMorningDeliverybooleanMorning delivery.
priceMorningDeliverynumberCents.
allowEveningDeliverybooleanEvening delivery.
priceEveningDeliverynumberCents.
allowSameDayDeliverybooleanSame-day (requires cutoffTimeSameDay).
priceSameDayDeliverynumberCents.
allowMondayDeliverybooleanMonday delivery.
priceMondayDeliverynumberCents.
allowSaturdayDeliverybooleanSaturday delivery.
priceSaturdayDeliverynumberCents.

Shipment options (per shipment, on top of the delivery option)

KeyTypePurpose
allowSignaturebooleanSignature on receipt.
priceSignaturenumberCents.
allowOnlyRecipientbooleanDeliver only to the addressee.
priceOnlyRecipientnumberCents.
allowPriorityDeliverybooleanPriority delivery (PostNL mailbox since v6.24, NL-only since v6.26.1).

Pickup

KeyTypePurpose
allowPickupLocationsbooleanShow the pickup tab.
pricePickupnumberCents.
excludeParcelLockersbooleanHide lockers (since v6.21).

Package types

KeyTypePurpose
packageType'package' | 'mailbox' | 'digital_stamp' | 'package_small'Pre-selected type.
pricePackageTypeMailboxnumberCents.
pricePackageTypeDigitalStampnumberCents.
pricePackageTypePackageSmallnumberCents.

Full type definition

The authoritative source for all keys: @myparcel-dev/do-shared — exported as InputDeliveryOptionsConfiguration and DeliveryOptionsConfiguration.

7 · Drop-off days and cutoff

Determines when an order still goes to the carrier the same day. This affects which delivery dates the widget shows.

Simple — one cutoff for all drop-off days

{
  cutoffTime: '16:00',
  sameDayCutoffTime: '09:30',
  dropOffDays: '1,2,3,4,5',     // Mon–Fri; also valid: [1,2,3,4,5] or '1;2;3;4;5'
  dropOffDelay: 0,              // days between order and drop-off
  deliveryDaysWindow: 7,        // how many days ahead are shown
}

A separate cutoff per day

{
  cutoffTime: '15:00',          // fallback
  sameDayCutoffTime: '09:30',
  dropOffDays: [
    1,                                // Monday — uses the fallback cutoff
    { day: 2, cutoffTime: '16:00', sameDayCutoffTime: '10:00' },
    { day: 3 },
    { day: 5, cutoffTime: '14:00' },
  ],
  closedDays: ['2026-12-25', '2026-12-26'],  // shop closure (since v6.19)
}

closedDays (v6.19.0+) blocks specific calendar dates without you having to rework dropOffDays.

cutoffTime without dropOffDays is deprecated

Since v6 you must define dropOffDays — otherwise the widget guesses Mon–Fri working days and you get incorrect "tomorrow" labels around public holidays.

8 · Pickup points

By default you get a list view; users can switch to a map when allowPickupLocationsViewSelection: true.

Custom map tiles (Mapbox / MapTiler)

pickupLocationsMapTileLayerData: {
  url: 'https://api.maptiler.com/maps/streets-v2/{z}/{x}/{y}.png?key=YOUR_KEY',
  attribution: '© MapTiler © OpenStreetMap contributors',
  minZoom: 1,
  maxZoom: 18,
}

Without this key the widget falls back to OpenStreetMap tiles.

Selection payload for pickup

{
  "carrier": "postnl",
  "date": "2026-04-12 00:00:00.000000",
  "deliveryType": "pickup",
  "isPickup": true,
  "packageType": "package",
  "pickupLocation": {
    "locationCode": "169177",
    "retailNetworkId": "PNPNL-01",
    "locationName": "Albert Heijn",
    "street": "Hoofdstraat",
    "number": "1",
    "postalCode": "1012AB",
    "city": "Amsterdam",
    "cc": "NL",
    "latitude": 52.3702,
    "longitude": 4.8952,
    "openingHours": { "monday": [{ "from": "08:00", "to": "20:00" }] }
  },
  "shipmentOptions": {}
}

9 · Handling the selection

The event payload maps 1-to-1 onto the options object of POST /shipments:

document.addEventListener('myparcel_updated_delivery_options', async (event) => {
  const choice = event.detail;

  await fetch('/api/checkout/delivery-choice', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      carrier:      choice.carrier,
      delivery_date: choice.date,
      delivery_type: choice.deliveryType,
      package_type:  choice.packageType,
      pickup:        choice.pickupLocation ?? null,
      options:       choice.shipmentOptions,
    }),
  });
});

Persist server-side, not just in localStoragelocalStorage doesn't survive a tab change or refresh cycle, and the choice belongs to the order, not the browser.

Validate server-side

Never trust the widget alone — repeat the validation server-side. A user can manipulate the payload via DevTools. The PHP/JS SDKs do this automatically through their consignment validators.

10 · Migrate v5 → v6

Main breaking changes (full story: §Upgrading on the old page ↗):

Whatv5v6
StylesheetAuto-injectedManually include dist/style.css
showDeliveryDatePer carrierGlobal — no longer per carrier (and deprecated since v6.26.0)
unselect_delivery_options eventExistedRemoved
cutoffTime without dropOffDaysAcceptableDeprecated — use dropOffDays
Vue 2DefaultVue 3 required (see myparcel.lib.js for "bring-your-own")

Versions since v6.18 (quick changelog)

VersionWhat
v6.26.1 (2026-02-23)Priority delivery NL-only.
v6.26.0 (2026-02-10)showDeliveryDate deprecated.
v6.25.0 (2026-01-27)Evening delivery for DHL For You.
v6.24.0 (2026-01-27)Priority delivery for PostNL mailbox.
v6.22.0 (2025-11-11)Trunkrs as a carrier.
v6.21.0 (2025-10-27)excludeParcelLockers added.
v6.20.0 (2025-10-10)Custom platform config via config.platform.
v6.19.0 (2025-10-09)closedDays for shop closures.
v6.18.0 (2025-08-14)Carrier-request caching.

Full changelog: apps/delivery-options/CHANGELOG.md ↗.

11 · Sandbox and debugging

12 · Combining with the SDKs

The widget event hands you the selection; the SDKs build consignments from it:

// PHP — via myparcelnl/sdk
use MyParcelNL\Sdk\Factory\DeliveryOptionsAdapterFactory;

$adapter = DeliveryOptionsAdapterFactory::create($_POST['delivery_choice']);
$consignment->setDeliveryDate($adapter->getDate())
            ->setDeliveryType($adapter->getDeliveryTypeId())
            ->setPackageType($adapter->getPackageTypeId());
// TypeScript — via @myparcelnl/sdk (JS SDK)
import { MyParcel } from '@myparcelnl/sdk';

const mp = new MyParcel({ /* ... */ });
const shipment = await mp.shipments.create({
  carrier:      choice.carrier,
  delivery_date: choice.date,
  recipient:    customerAddress,
  options:      { ...choice.shipmentOptions, package_type: choice.packageType },
});

See the PHP SDK and JavaScript SDK for the full consignment flow.