Latest version of myparcelnl/sdk on Packagist
myparcelnl/sdk issues on GitHub
myparcelnl/sdk pull requests on GitHub



The MyParcel SDK works with PHP version >= 7.1.

If you have a PHP version lower than 7.1 then we would like to advise you to update your PHP version to a supported version. For support for PHP version 5.6 you can use release 2.x.

Installation with Composer

This SDK uses Composer. Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on, and it will manage (install/update) them for you. For more information on how to use composer, please visit the Composer website

To install the MyParcel SDK into your project, simply use

composer require myparcelnl/sdk

You can then start using our classes in the namespace MyParcelNL/Sdk.


Create a consignment

This example uses only the required methods to create a shipment and download its label.

$consignment = (ConsignmentFactory::createByCarrierId(PostNLConsignment::CARRIER_ID))
    ->setPerson('Piet Hier')
    ->setFullStreet('Plein 1945 55b')
    ->setLabelDescription('Order 146');

$consignments = (new MyParcelCollection())

$consignmentId = $consignments->first()->getConsignmentId();


Using multiple carriers

It is possible to use multiple carriers. The following carriers are supported:

IDNameCarrier classConsignment class

You can query which carriers are available like this:

$options = (new CarrierOptionsWebService())

You can get the required shop_id from AccountWebService, the only shop returned will be the shop belonging to the API key that is used. Since the shop_id will not change unless the API key changes, we advise you to store the shop_id until the user updates the API key.

$shopId = (new AccountWebService())

Create a consignment for each carrier manually

$postNL   = new \MyParcelNL\Sdk\Model\Consignment\PostNLConsignment();
$bpost    = new \MyParcelNL\Sdk\Model\Consignment\BpostConsignment();
$dpd      = new \MyParcelNL\Sdk\Model\Consignment\DPDConsignment();

Or by using Factory\ConsignmentFactory with a carrier ID or name, making it easier to dynamically instantiate a consignment:

use MyParcelNL\Sdk\src\Factory\ConsignmentFactory;
use MyParcelNL\Sdk\src\Model\Carrier\CarrierBpost;
use MyParcelNL\Sdk\src\Model\Carrier\CarrierPostNL;

$postNL = ConsignmentFactory::createByCarrierId(CarrierPostNL::getId());
$bpost  = ConsignmentFactory::createByCarrierName(CarrierBpost::getName());

Create multiple consignments

This example creates multiple consignments by adding them to one MyParcelCollection() and then creates and downloads one PDF with all labels.

// Create the collection before the loop
$consignments = (new MyParcelCollection())
    ->setUserAgents(['name_of_cms', '1.0']);

// Loop through your shipments, adding each to the same MyParcelCollection
foreach ($yourShipments as $yourShipment) {
    $consignment = ((ConsignmentFactory::createByCarrierId(PostNLConsignment::CARRIER_ID))

    // Add each consignment to the collection created before

Create return-in-the-box

This example creates a consignment and a related return consignment by adding them to one MyParcelCollection() and then creates and downloads a single PDF file with both labels.

// Create the collection before the loop
$consignments = new MyParcelCollection();

// Loop through your shipments, adding each to the same MyParcelCollection
foreach ($yourShipments as $yourShipment) {
    $consignment = ((ConsignmentFactory::createByCarrierId(PostNLConsignment::CARRIER_ID))

    // Add the consignment to the collection and generate the return consignment
    // When there are no options set, the options from the parent consignment are used
            function (
                AbstractConsignment $returnConsignment,
                AbstractConsignment $parent
            ): AbstractConsignment {
                    'Return: ' . $parent->getLabelDescription() .
                    ' This label is valid until: ' . date("d-m-Y", strtotime("+ 28 days"))

                return $returnConsignment;

Label format and position

Choose to output the label as either A4 or A6 when creating a pdf or download link with the argument $positions of setPdfOfLabels($positions) and setLinkOfLabels($positions).

Example values for $positions:

A4:            A6:
┏━━━━━┳━━━━━┓  ┏━━━━━┓
┃  1  ┃  2  ┃  ┃  x  ┃
┣━━━━━╋━━━━━┫  ┗━━━━━┛
┃  3  ┃  4  ┃
  1. 1: Default value. Outputs A4, starting at top left position.
  2. false: Outputs at A6 format
  3. [1,4]: Defines the position of labels on an A4 sheet. Only applies to the first page, subsequent pages will use the default positioning (1,2,3,4)

For more information, see 6_F.

Package types and options

Set package type with setPackageType($type). Retrieve it afterwards with getPackageType().

For more details on the different package types, see 6_A_1.

Package types


id: 1

This is the default package type. It must be explicitly set to allow enabling of further shipment options. It's available for NL, EU and global shipments.

Mailbox package

id: 2

This package type is only available for NL shipments that fit into a mailbox. It does not support additional options.

If you still make the request with additional options, bear in mind that you may pay more than the actual shipment costs!


id: 3

This package type is available for NL, EU and global shipments. The label for this shipment is unpaid meaning that you will need to pay the postal office/courier to send this letter/package. Therefore, it does not support additional options.

Digital stamp

id: 4

This package type is only available for NL shipments and does not support any additional options. Its price is calculated using the package weight, which is set using setPhysicalProperties().

This type of shipment will be billed the moment it is printed. Read more in 6_A_1.

Package options

These options are only available for package-type 1 (package).

Available options:

  • only_recipient: Deliver the package only at address of the intended recipient. This option is required for Morning and Evening delivery types.
    • Set: setOnlyRecipient(true)
    • Get: isOnlyRecipient()
  • signature: Recipient must sign for the package. This option is required for Pickup delivery type.
    • Set: setSignature(true)
    • Get: isSignature()
  • return: Return the package to the sender when the recipient is not home.
    • Set: setReturn(true)
    • Get: isReturn()
  • large_format: This option must be specified if the dimensions of the package are between 100 x 70 x 50 and 175 x 78 x 58 cm. If the scanned dimensions from the carrier indicate that this package is large format, and it has not been specified then it will be added to the shipment in the billing process. This option is also available for EU shipments.
    • Set: setLargeFormat(true)
    • Get: isLargeFormat()
  • age_check: The Customer/Consumer must sign for the package and only receive it when he is at least 18 years.
    • Set: setAgeCheck(true)
    • Get: hasAgeCheck()
  • insurance: This option allows a shipment to be insured up to certain amount. NL shipments can be insured for € 5000,–. EU shipments must be insured for € 500,–. Global shipments must be insured for € 200,–. The following shipment options are mandatory when insuring an NL shipment: only_recipient and signature.
    • Set: setInsurance(250) (amount in EUR)
    • Get: getInsurance()


package-type 1 (package) with all shipment options:
(new PostNLConsignment())
    // Other options...
package-type 4 (digital_stamp), with mandatory weight:
(new PostNLConsignment())
    // weight in grams (required)
    ->setPhysicalProperties(['weight' => 300]);

For more information, see 6_A_3.

Find consignments

After creating consignments, it is often necessary to pick up a specific consignment:

$consignments = MyParcelCollection::find(432345);

Instead of find() you can also use findMany(), findByReferenceIdentifier() or findManyByReferenceIdentifier().

For reference identifier you can use a * to search smarter:

$consignments = MyParcelCollection::findByReferenceIdentifier('order-14*');

Query consignments

You can search and filter consignments by certain values:

$consignments = MyParcelCollection::query(
        'q'                    => 'Niels',
        'reference_identifier' => 'order-1234',
        'status'               => 2,
        'from'                 => '2020-01-01 00:00:00',
        'to'                   => '2020-02-01 00:00:00',
        'page'                 => 1,
        'size'                 => 200,
        'order'                => 'DESC',
        'package_type'         => 1,
        'region'               => 'NL;EU',
        'dropoff_today'        => 1,

For q and reference identifier you can use * (wildcards) to search smarter.

If the 2nd parameter is an object, then public properties will be used. If you query in many ways, creating a separate class can provide a clean solution.

For more information, see 6_E.

Retrieve data from a consignment

Most attributes that have a set<Attribute>() method also have a get<Attribute>() method to retrieve the data. View all methods for consignments.

$consignment = new PostNLConsignment();

echo $consignment->getFullStreet();
echo $consignment->getPerson();
echo $consignment->getPhone();
echo $consignment->getStreet();
// etc...
Get status

After setPdfOfLabels(), setLinkOfLabels() and createConcepts() you can get the status.

$status = $consignment->getStatus();
Get barcode

The barcode is available after setPdfOfLabels() and setLinkOfLabels()

$barcode = $consignment->getBarcode();
Get Track & Trace URL

The Track & Trace URL is available after downloadPdfOfLabels() and getLinkOfLabels()

$consignment = (new \MyParcelNL\Sdk\src\Model\Consignment\PostNLConsignment());
echo $consignment->getBarcodeURL('3SMYPA123456789', '2231JE', 'NL'); // Barcode , Postal code, Country

Create and download label(s)

Create and directly download PDF with setPdfOfLabels($position) where $positions is the label position value.

    // Opens pdf "inline" by default, pass false as argument to download file instead

Create and echo download link to PDF with setLinkOfLabels($position) where $positions is the label position value. If you want more than 25 labels in one response, setLinkOfLabels will automatically use a different endpoint. At that point, it is likely that the PDF is not ready yet. You should check periodically if the PDF is ready for download.

echo $consignments

If you want to download a label at a later time, you can also use the following to fill the collection:

$consignments = MyParcelCollection::findByReferenceIdentifier('order-146', 'api_key_from_backoffice');

Instead of findByReferenceIdentifier() you can also use findManyByReferenceIdentifier(), find() or findMany().

For more information, see 6_F.

Create and save orders

Start by creating an OrderCollection and setting your API key:

use MyParcelNL\Sdk\src\Collection\Fulfilment\OrderCollection;

$orderCollection = (new OrderCollection())

Define the billing and shipping addresses of the order with the Recipient class.

use MyParcelNL\Sdk\src\Model\Recipient;

$address = (new Recipient())
    ->setPerson('Ms. Parcel')
    // Note: This field includes house number and number suffix.
    ->setStreet('Antareslaan 31')

Create an Order:

use MyParcelNL\Sdk\src\Model\Fulfilment\Order;

$order = (new Order())
    // The unique identifier of the order in your webshop.
    // Shipping address of the customer.
    // Invoice/billing address of the customer.
    // The delivery options. Must be an instance of AbstractDeliveryOptionsAdapter.
    // The date when the order was placed. Can be a DateTime object or a string in Y-M-d H:i:s format.
    ->setOrderDate(new DateTime());

To create order lines, you'll probably want to loop over the order lines from the order in your webshop. Every Order should contain one or more order lines.

use MyParcelNL\Sdk\src\Model\Fulfilment\OrderLine;

$orderLine = (new OrderLine())
    // Full price in cents, regardless of quantity, excluding VAT.
    // Full price in cents, regardless of quantity, including VAT.
    // VAT in cents.
    // Amount of Products in this OrderLine.
    // Arbitrary key/value instructions. Currently unused.
        'wrapping' => 'the blue one with kittens on it'

An order line stores its product data in Product. You can set product data in two different ways:

By getting the Product and setting properties on there. When an OrderLine is created an empty Product is always created:

     // Product name.
    ->setName('Long Sleeved Button Up Shirt')
    // Additional product description.
    ->setDescription('White and blue')
    // Stock Keeping Unit of the product.
    // The unique identifier of the product in your webshop software.
    // Weight in grams
    // Height in millimeters
    // Length in millimeters
    // Width in millimeters

Or by creating a Product separately and using OrderLine::setProduct().

use MyParcelNL\Sdk\src\Model\Fulfilment\Product;

$product = new Product();
// You can use the same setters from the example above.


Finally, add the created OrderLine to the order:


And add the order to the OrderCollection


When the order is complete, save it to our API by using the save method.

$savedOrderCollection = $orderCollection->save();
Full example
use MyParcelNL\Sdk\src\Collection\Fulfilment\OrderCollection;
use MyParcelNL\Sdk\src\Model\Fulfilment\Order;
use MyParcelNL\Sdk\src\Model\Fulfilment\OrderLine;
use MyParcelNL\Sdk\src\Model\Recipient;

$orderCollection = (new OrderCollection())

$customerAddress = (new Recipient())
    ->setPerson('Ms. Parcel')
    ->setStreet('Antareslaan 31')

$order = (new Order())
    ->setOrderDate(new DateTime());

foreach ($orderLines as $orderLineData) {
    $orderLine = (new OrderLine())
            'wrapping' => 'the blue one with kittens on it'




$savedOrderCollection = $orderCollection->save();

Adding order notes to an order

It is possible to add notes to an order. These notes are visible in the backoffice. A note can be either a customer note or a webshop note. A webshop note can be created in the admin panel of an e-commerce platform.

To add a note to an order, simply create an OrderNote and add it to an OrderNoteCollection. Then, save the collection to our API.

use MyParcelNL\Sdk\src\Model\Fulfilment\OrderNote;
use MyParcelNL\Sdk\src\Collection\Fulfilment\OrderNoteCollection;

$orderNoteCollection = new OrderNoteCollection();
$orderNote           = new OrderNote([
    'orderUuid' => 'uuid_of_order', // You need the uuid generated by our API.
    'note'      => 'This is a note',
    'author'    => 'webshop', // This can be either 'webshop' or 'customer'.


// This will send the order note to our API. Thanks to the uuid, the note will
// be placed in the correct order.
$savedOrderNoteCollection = $orderNoteCollection->save();

Note: The uuid of an order can be found in the response of the save method of the OrderCollection. Therefore, you need to save the order first before you can add notes to it.

Setting up webhooks

You can use our webhooks to keep track of changes in shipments, labels and your shop settings in the most efficient way.

Do note that most of our webhooks do not send a lot of data in the payload. They are more like a notification with a few properties to allow you to decide to proceed to send another request or not. This is for increased security and to reduce unnecessary bandwidth usage.


  • Your website must use HTTPS.

Registering a webhook

Register a webhook by instantiating the WebhookWebService you want, passing your API key and executing subscribe with the URL you want to receive the payloads. You can only have one subscription to each webhook.

$service = new \MyParcelNL\Sdk\src\Services\Web\Webhook\ShipmentStatusChangeWebhookWebService();

$webhookId = $service

// Save $webhookId somewhere safe.

ShipmentStatusChangeWebhookWebService can be any of the services described in Available Webhooks.

Deleting a webhook

To delete a webhook, you need to pass your API key and the numeric id you've received when registering the webhook.

$service = new \MyParcelNL\Sdk\src\Services\Web\Webhook\ShipmentStatusChangeWebhookWebService();


In case you lost the ID, you can do an authenticated call to to retrieve it. You can also subscribe to the same endpoint again, which will remove the old subscription.

Available webhooks


Triggered when any shipment's status changes. This is the recommended way to keep track of shipment statuses.


For more information, see 11_B


Triggered when any label is printed/created.


For more information, see 11_C


Triggered when the shop is updated.



Example: After saving the "General Settings" section in the backoffice.

  "data": {
    "hooks": [
        "shop_id": 12345,
        "attributes": ["general_settings", "modified"],
        "event": "shop_updated"



Triggered when the carrier configuration in a shop is updated, for example when a different drop-off point is selected.


Example: After changing the default drop-off time for PostNL from 16:00 to 16:30.

  "data": {
    "hooks": [
        "shop_id": 58585,
        "event": "shop_carrier_configuration_updated"




Example: After disabling a carrier in the backoffice.

  "data": {
    "hooks": [
        "shop_id": 12345,
        "event": "shop_carrier_accessibility_updated"





Set consignment attributes

$consignment = (new \MyParcelNL\Sdk\src\Model\Consignment\PostNLConsignment())
    ->setReferenceIdentifier('order-146') // Not visible on the label

    // Recipient/address:
    ->setPerson('Piet Hier')    // Name
    ->setEmail('')  // E-mail address
    ->setPhone('+31 612345678') // Phone number
    ->setCompany('Piet BV')     // Company

    // Preferred: Street, number and suffix in one line
    ->setFullStreet('Plein 1945 55b')
    // Alternatively, you can send the street data separately:
    ->setStreet('Plein 1945') // Street
    ->setNumber(55)           // Number
    ->setNumberSuffix('b')    // Suffix

    ->setStreetAdditionalInfo('2 hoog') // Additional info

    ->setCity('Amsterdam')    // City
    ->setPostalCode('2231JE') // Postal code
    ->setCountry('NL')        // Country

    // Available package types:
    // 1: Package (default)
    // 2: Mailbox package
    // 3: Letter
    // 4: Digital stamp

     * @see "Package type and options > Package types"
    // Deliver the package only at address of the intended recipient. This option is required for Morning and Evening delivery types.
    // Recipient must sign for the package. This option is required for Pickup delivery type.
    // Return the package to the sender when the recipient is not home.
    // Must be specified if the dimensions of the package are between 100x70x50 and 175x78x58 cm.
    // Allows a shipment to be insured up to certain amount. Only packages (package type 1) can be insured.

    ->setLabelDescription('Order 146') // This description will appear on the shipment label (for package type 1)

    // Delivery:

    // Set pickup location
    ->setPickupPostalCode('1234 AB')

    // Physical properties
    ->setPhysicalProperties(['weight' => 73]) // Array with physical properties of the shipment. Currently, only used to set the weight in grams for digital stamps (which is required)

    // Auto detect pickup
    ->setAutoDetectPickup(true) // When this setting is false MyParcel do not auto-detect a PostNL pickup addresses.

    // Save recipient address
    ->setSaveRecipientAddress(true) // When this setting is true the recipient address will be saved in the address book.

    // Non-EU shipment attributes: see

Get consignment attributes

    // Barcode is available after using setLinkOfLabels() or setPdfOfLabels() on the MyParcelCollection the consignment has been added to


    // Recipient info

    // It doesn't matter whether you used setFullStreet() or set all parts separately

    // Package type

    // Get value of options

    // Get pickup location info

    // Delivery

    // Physical properties (digital stamps or non-EU shipments)

    // Non-EU attributes

This object is embedded in the PostNLConsignment object for global shipments and is mandatory for non-EU shipments.


  ->setAmount(3) // Amount of items in the package

  // ISIC/IDEP code (
  ->setClassification(0111) // Example: 0111 = "Growing of cereals (except rice), leguminous crops and oil seeds"
  ->setCountry('NL') // Country of origin
  ->setDescription('Cereal grains')
  ->setItemValue(40000) // Price of item in cents
  ->setWeight() // The total weight for these items in whole grams. Between 0 and 20000 grams.





Stores all consignments to communicate with the MyParcel API. MyParcelCollection also contains almost all methods from Laravel Collections. If you use Laravel it also extends \Illuminate\Support\Collection.


    // Add consignment to collection
    // Generate the return consignments based on already added consignments

    // Get consignments from the collection

    // Clear the collection

    // Create or delete concept shipments in the MyParcel Backoffice


    // Send return label to customer. The customer can pay and download the label
    // Set id and run this function to update all the information about this shipment


    // Refer to

    // To give us insight into which CMS you're connecting from, you should send a User-Agent.
    // If you're using a known CMS it's required.
    // You must send the name of the CMS (required) followed by a version number (optional).
    ->setUserAgents(['name_of_cms', '1.0'])

Delivery options from the checkout with adapters

You can use DeliveryOptionsAdapterFactory if you use our Delivery Options module in your checkout. You can use these adapters to receive the options anywhere in your code in a consistent way. If you also have the options in a different format, you can also make your own adapter.

use MyParcelNL\Sdk\src\Adapter\DeliveryOptions\DeliveryOptionsFromOrderAdapter;
use MyParcelNL\Sdk\src\Factory\DeliveryOptionsAdapterFactory;

try {
	// Create new instance from known json
	$deliveryOptions = DeliveryOptionsAdapterFactory::create(json_decode($dataFromCheckout));
} catch (BadMethodCallException $e) {
	// Create new instance from your own data
	$deliveryOptions = new DeliveryOptionsFromOrderAdapter(null, (array) $meta);

Adapters are independent of consignments. It is therefore your responsibility to transform an adapter into a consignment.


MyParcel uses several types of Exceptions to make the errors clear. It is your responsibility to provide the correct status in a response. These are the Exceptions that we currently use.


Exception to be returned when an address is incorrect or not usable.

Class: MyParcelNL\Sdk\src\Exception\InvalidConsignmentException

HTTP status: HTTP 412 Precondition Failed


Exception to be returned when a call to MyParcel services has failed.

Class: MyParcelNL\Sdk\src\Exception\ApiException

HTTP status: HTTP 502 Bad Gateway


Exception thrown when there is an attempt to dynamically access a field that does not exist.

Class: MyParcelNL\Sdk\src\Exception\MissingFieldException

HTTP status: HTTP 500 Internal Server Error


Exception thrown if an argument is not the expected name.

Class: \InvalidArgumentException

HTTP status: HTTP 500 Internal Server Error


Exception thrown if a callback refers to an undefined method or if some arguments are missing.

Class: \BadMethodCallException:

HTTP status: HTTP 500 Internal Server Error


This SDK is not only useful for communicating with MyParcel, but also contains code that you can take advantage of yourself.


If you use arrays a lot, Collections are usually better to work with.

Other helpers

  • \MyParcelNL\Sdk\src\Support\Arr documentation
  • \MyParcelNL\Sdk\src\Support\Str documentation
  • \MyParcelNL\Sdk\src\Helper\SplitStreet::splitStreet('Plein 1940-45 3b'))


Please read our contribution guidelines on GitHub.

Edit this page
Last updated: 
Contributors Richard Perdaan