PHP SDK

Technische referentie voor het officiële myparcelnl/sdk Composer-package. Behandelt installatie, de consignment-levenscyclus, carriers, labels, retouren, de Fulfilment Order API en direct printen.

In het kort

De PHP SDK verpakt de MyParcel REST API in een typed object-model: bouw een Consignment, gooi 'm in een MyParcelCollection, verstuur. De SDK regelt request-signing, label-rendering en PDF-stitching. Alles is open source onder MIT op github.com/myparcelnl/sdk ↗.

Wat zoek je?

DoelSectie
Installeren en eerste shipment versturen1 · Install → 4 · Quickstart
Carrier kiezen en hun mogelijkheden zien6 · Carriers
Pakkettype, delivery type, shipment options7 · Consignment opties
Labels in PDF (A4/A6) genereren9 · Labels en printen
Track & Trace ophalen10 · Track & Trace
Bestaande consignments terugzoeken11 · Queryen en terughalen
Retouren aanmaken12 · Retouren
Order API (Fulfilment) gebruiken13 · Order API (Fulfilment)
Errors afhandelen15 · Exceptions
Migreren van een oudere versie17 · Migreren

Status van deze pagina

De oude variant op developer.myparcel.nl/documentation/50.php-sdk.html ↗ is verouderd (PHP 7.1, namespace MyParcel\Sdk). Deze pagina is geschreven tegen myparcelnl/sdk v10.7+ en gebruikt de huidige namespace MyParcelNL\Sdk\.

1 · Install

composer require myparcelnl/sdk

PSR-4 autoload — geen handmatige require nodig. Bron: Packagist ↗.

Requirements

Versie
PHP7.4 of 8.x (8.1+ aanbevolen, 8.4 ondersteund vanaf v10.3.6)
Composer2.x
Extensiesext-curl, ext-json, ext-mbstring
Runtime depssetasign/fpdf ^1.8, setasign/fpdi ^2.6 (label-stitching)

Composer constraint: "php": "^7.4 || ^8.0". Lagere PHP-versies dan 7.4 worden niet meer ondersteund.

2 · Architectuur in één oogopslag

De SDK volgt drie lagen:

Carrier  ──►  Consignment  ──►  MyParcelCollection
( ID/naam)    (één pakket)      (batch + label-IO)
  • Carrier — een statisch model per vervoerder met ID, NAME en bijbehorende Consignment-class. Zie src/Model/Carrier.
  • Consignment — alle data van één pakket (afzender, ontvanger, opties, fysieke eigenschappen). Carrier-specifieke subklassen (bv. PostNLConsignment) bepalen welke delivery_type, package_type en shipment_option-combinaties zijn toegestaan. Zie src/Model/Consignment.
  • MyParcelCollection — verzamelt consignments, praat met de API (POST /shipments, /shipment_labels, /track_traces), genereert PDF-labels en regelt multi-collo. Zie src/Helper/MyParcelCollection.php.

Top-level namespaces:

NamespaceDoel
MyParcelNL\Sdk\FactoryConsignmentFactory, DeliveryOptionsAdapterFactory
MyParcelNL\Sdk\Model\CarrierCarrier-classes en CarrierFactory
MyParcelNL\Sdk\Model\ConsignmentAbstractConsignment + per-carrier subklassen
MyParcelNL\Sdk\Model\FulfilmentOrder, OrderLine, OrderNote, Product
MyParcelNL\Sdk\HelperMyParcelCollection, LabelHelper, TrackTraceUrl, Utils
MyParcelNL\Sdk\ServicesEncoders en CountryService
MyParcelNL\Sdk\ExceptionAlle SDK-exceptions

3 · Authenticatie

De SDK authenticeert per request met een shop-API-key (Basic auth). Geen OAuth-flow op SDK-niveau — token-uitwisseling regelt de SDK intern als de API dat vereist.

$apiKey = getenv('MYPARCEL_API_KEY'); // base64-encoded shop key uit de backoffice

Hoe de key gebruikt wordt:

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

$consignment = ConsignmentFactory::createByCarrierId(CarrierPostNL::ID)
    ->setApiKey($apiKey);

setApiKey() staat op elke consignment, dus mixen van keys binnen één collection is mogelijk — handig voor multi-shop integraties.

Key-hygiëne

Bewaar keys serverside in env vars, secret manager of .env (buiten VCS). Lever ze nooit naar de browser. De API rate-limit zit op de key — een gelekte key is direct misbruikbaar.

User-agent (verplicht voor integraties)

Plugins en eigen integraties moeten zichzelf identificeren — anders is debuggen onmogelijk en kan MyParcel niet zien wat een issue veroorzaakt.

$consignment->setUserAgentForProposition('CustomShop', '2.4.1');

setUserAgentForProposition(string $proposition, ?string $version) is de nieuwe API; setUserAgent() is deprecated en verdwijnt in de volgende major. De SDK voegt zelf MyParcelNL-SDK/<sdkVersion> en php/<phpVersion> toe aan de header.

4 · Quickstart — eerste zending

Eén consignment, één label, A6-PDF op disk.

<?php
require 'vendor/autoload.php';

use MyParcelNL\Sdk\Factory\ConsignmentFactory;
use MyParcelNL\Sdk\Helper\MyParcelCollection;
use MyParcelNL\Sdk\Model\Carrier\CarrierPostNL;
use MyParcelNL\Sdk\Model\Consignment\AbstractConsignment;

$apiKey = getenv('MYPARCEL_API_KEY');

$consignment = (ConsignmentFactory::createByCarrierId(CarrierPostNL::ID))
    ->setApiKey($apiKey)
    ->setReferenceIdentifier('ORDER-2026-01042')
    ->setCountry(AbstractConsignment::CC_NL)
    ->setPerson('J. de Vries')
    ->setFullStreet('Antwoordnummer 42')
    ->setPostalCode('1012AB')
    ->setCity('Amsterdam')
    ->setEmail('test@example.com')
    ->setPackageType(AbstractConsignment::PACKAGE_TYPE_PACKAGE)
    ->setLabelDescription('Order #146');

(new MyParcelCollection())
    ->addConsignment($consignment)
    ->setUserAgentForProposition('CustomShop', '2.4.1')
    ->setPdfOfLabels()           // POST /shipments + GET /shipment_labels
    ->downloadPdfOfLabels();     // streamt de PDF naar de browser

Wat er onder de motorkap gebeurt: de collection roept POST /shipments aan, krijgt consignment-ID's terug, vraagt vervolgens labels op via GET /shipment_labels/{ids} en stitcht die in één PDF.

5 · Builder-conventies

  • Fluent setters. Elke setter geeft $this terug — chain ze.
  • Constants boven strings. PACKAGE_TYPE_PACKAGE (= 1) en DELIVERY_TYPE_STANDARD (= 2) zijn beter leesbaar dan magic numbers en breken niet als de API rangetjes uitbreidt.
  • Validators draaien automatisch. Per carrier zit er een *ConsignmentValidator die toegestane combinaties afdwingt. Een setSignature(true) op een carrier die dat niet ondersteunt gooit een InvalidConsignmentException.
  • getAllowed*()-methodes. Vraag een consignment vóór gebruik welke opties geldig zijn:
    $consignment->getAllowedDeliveryTypes();   // ['morning','standard','evening','pickup']
    $consignment->getAllowedPackageTypes();    // ['package','mailbox','letter','digital_stamp','package_small']
    $consignment->getAllowedShipmentOptions(); // ['age_check','insurance','large_format', ...]
    

6 · Carriers

Iedere carrier heeft een ID (numeriek, gebruikt door de API) en een NAME (slug, gebruikt in naam-gebaseerde factory-aanroepen).

CarrierClassIDNAME
PostNLCarrierPostNL1postnl
bpostCarrierBpost2bpost
DPDCarrierDPD4dpd
DHL For YouCarrierDHLForYou9dhlforyou
DHL Parcel ConnectCarrierDHLParcelConnect10dhlparcelconnect
DHL EuroplusCarrierDHLEuroplus11dhleuroplus
UPS StandardCarrierUPSStandard12upsstandard
UPS Express SaverCarrierUPSExpressSaver13upsexpresssaver
GLSCarrierGLS14gls
TrunkrsCarrierTrunkrs16trunkrs
use MyParcelNL\Sdk\Factory\ConsignmentFactory;

ConsignmentFactory::createByCarrierId(2);            // bpost
ConsignmentFactory::createByCarrierName('dhlforyou'); // DHL For You

Welke carriers zijn beschikbaar voor mijn account?

Beschikbaarheid is contractueel — niet elke carrier zit in elk shop-contract. De API geeft een 403/validation error als je een niet-geactiveerde carrier gebruikt.

7 · Consignment-opties

Package types

Het type bepaalt afmetingsregels en welke shipment-opties beschikbaar zijn. Per carrier verschillend; check getAllowedPackageTypes().

ConstantIDNaamWanneer
PACKAGE_TYPE_PACKAGE1packageStandaard pakket. Default.
PACKAGE_TYPE_MAILBOX2mailboxBrievenbuspakje (≤ 2 cm dik, NL-only).
PACKAGE_TYPE_LETTER3letterOnverzekerde brief, geen track & trace.
PACKAGE_TYPE_DIGITAL_STAMP4digital_stampDigitale postzegel — wel sturing nodig om gewicht.
PACKAGE_TYPE_PACKAGE_SMALL6package_smallKlein pakket (PostNL).

Delivery types

ConstantIDNaam
DELIVERY_TYPE_MORNING1morning
DELIVERY_TYPE_STANDARD2standard (default)
DELIVERY_TYPE_EVENING3evening
DELIVERY_TYPE_PICKUP4pickup
DELIVERY_TYPE_EXPRESS7express

Pickup-zendingen hebben een PickupLocation nodig — zet via setPickupLocation(new PickupLocation([...])).

Shipment options

Booleaanse extra's bovenop het basisvervoer.

ConstantAPI-keySetter
SHIPMENT_OPTION_SIGNATUREsignaturesetSignature(bool)
SHIPMENT_OPTION_ONLY_RECIPIENTonly_recipientsetOnlyRecipient(bool)
SHIPMENT_OPTION_AGE_CHECKage_checksetAgeCheck(bool)
SHIPMENT_OPTION_INSURANCEinsurancesetInsurance(int $cents)
SHIPMENT_OPTION_LARGE_FORMATlarge_formatsetLargeFormat(bool)
SHIPMENT_OPTION_RETURNreturnsetReturn(bool)
SHIPMENT_OPTION_PRINTERLESS_RETURNprinterless_returnsetPrinterlessReturn(bool)
SHIPMENT_OPTION_HIDE_SENDERhide_sendersetHideSender(bool)
SHIPMENT_OPTION_SAME_DAY_DELIVERYsame_day_deliverysetSameDayDelivery(bool)
SHIPMENT_OPTION_PRIORITY_DELIVERYpriority_deliverysetPriorityDelivery(bool) (sinds v10.7.0)
SHIPMENT_OPTION_RECEIPT_CODEreceipt_codesetReceiptCode(bool)
SHIPMENT_OPTION_COLLECTcollectsetCollect(bool)
SHIPMENT_OPTION_FRESH_FOODfresh_foodsetFreshFood(bool)
SHIPMENT_OPTION_FROZENfrozensetFrozen(bool)

Geldige combinaties

Niet alle opties zijn met elkaar te combineren — bv. receipt_code + signature is geblokkeerd. De per-carrier validator gooit InvalidConsignmentException met de exacte regel die overtreden wordt.

Verzekering

Bedragen in eurocent. De toegestane maxima per land vraag je op met getInsurancePossibilities(?string $cc):

$consignment->getInsurancePossibilities('NL'); // [0, 100, 250, 500, ..., 50000]
$consignment->setInsurance(50000);             // €500

Multi-collo (één label-stroom voor meerdere colli)

Voor zendingen die fysiek uit meerdere colli bestaan maar logistiek bij elkaar horen:

(new MyParcelCollection())
    ->addMultiCollo($consignment, 3)        // 1 hoofdcollo + 2 vervolgcolli
    ->setPdfOfLabels()
    ->downloadPdfOfLabels();

Werkt alleen op carriers die multi-collo aanbieden (getAllowedExtraOptions() bevat 'multi_collo').

8 · MyParcelCollection — batch-API

MyParcelCollection is een Laravel-stijl collection met SDK-specifieke methods. Belangrijkste publieke API:

MethodDoel
addConsignment($c)Voeg één consignment toe.
addMultiCollo($c, $amount)Multi-collo (zie boven).
addMultiColloConsignments(array $cs)Reeds-gegroepeerde set in één keer toevoegen.
createConcepts()POST /shipments voor de hele batch.
setLatestData(int $size = 300)Hydrate consignments met server-data (status, barcode, IDs).
setLinkOfLabels($pos = 1)Vraag download-link voor labels-PDF op.
setPdfOfLabels($pos = 1)Vraag PDF-bytes op (intern aanroepbaar door downloadPdfOfLabels).
downloadPdfOfLabels($inline = false)Stream PDF naar de browser (Content-Disposition: attachment of inline).
getLabelPdf() / getLinkOfLabels()Raw PDF-string of label-link na setPdfOfLabels()/setLinkOfLabels().
printDirect(string $printerGroupId)Stuur direct naar een gekoppelde printer. Vereist v10.6.0+.
generateReturnConsignments(bool $sendMail, ?Closure $modifier)Maak retourzendingen aan op basis van bestaande pakketten.
fetchTrackTraceData()Haal track & trace-historie op.
addConsignmentByConsignmentIds(array $ids, string $apiKey)Hydrate een collection vanuit bestaande shipment-IDs.
addConsignmentByReferenceIds($ids, $apiKey)Idem op reference_identifier.

Volgorde van calls in de typische workflow:

addConsignment*() → setLinkOfLabels() of setPdfOfLabels()
                 → downloadPdfOfLabels() of getLabelPdf()
                 → (optioneel) fetchTrackTraceData()

setPdfOfLabels() en setLinkOfLabels() triggeren intern createConcepts() als dat nog niet gebeurd is — je hoeft het zelden expliciet aan te roepen.

9 · Labels en printen

A6 versus A4

Default papierformaat is A6. Voor A4-vellen met meerdere labels per pagina geef je een positie mee:

// A6, één label per pagina
$collection->setPdfOfLabels()->downloadPdfOfLabels();

// A4, label op positie 1 (linksboven), 2 (rechtsboven), 3 (linksonder), 4 (rechtsonder)
$collection->setPdfOfLabels(2)->downloadPdfOfLabels();

// A4, vanaf positie 1, automatisch doorvullen
$collection->setPdfOfLabels(1)->downloadPdfOfLabels();

Posities 1–4 zijn alleen relevant voor A4. Op A6 wordt het argument genegeerd.

Direct printen (v10.6.0+)

Voor klanten met een gekoppelde label-printer in de MyParcel backoffice:

$collection
    ->setLinkOfLabels()
    ->printDirect('printer-group-uuid-here');

Het printerGroupId haal je uit de backoffice — Settings → Printers. Direct printen vraagt geen PDF aan op disk; de printserver krijgt de zending direct toegewezen.

$url = $collection->setLinkOfLabels()->getLinkOfLabels();
// signed URL, kort geldig — geschikt voor e-mail of UI-link

10 · Track & Trace

Eerst de consignments hydraten, dan T&T-data ophalen:

$collection
    ->setLatestData()         // status + barcode
    ->fetchTrackTraceData();  // history events

foreach ($collection->getConsignments() as $c) {
    echo $c->getBarcode();
    echo $c->getBarcodeUrl(
        $c->getBarcode(),
        $c->getPostalCode(),
        $c->getCountry()
    );
}

getBarcodeUrl() levert de publieke track-and-trace-URL. Plakt veilig in een e-mail naar de eindklant.

Status-constanten op AbstractConsignment:

ConstantBetekenis
STATUS_CONCEPT (1)Aangemaakt, label nog niet geprint.
Hogere waardesGeprint, overgedragen, in transit, afgeleverd, retour. Vraag de actuele lijst op via /shipments ↗.

11 · Queryen en terughalen

Op consignment-ID

$collection = (new MyParcelCollection())
    ->addConsignmentByConsignmentIds([12345678, 12345679], $apiKey)
    ->setLatestData();

Op reference identifier

$collection = (new MyParcelCollection())
    ->addConsignmentByReferenceIds(['ORDER-2026-01042'], $apiKey)
    ->setLatestData();
$collection = MyParcelCollection::query($apiKey, [
    'q'      => 'de Vries',
    'status' => AbstractConsignment::STATUS_CONCEPT,
    'from'   => '2026-04-01 00:00:00',
    'to'     => '2026-05-01 00:00:00',
    'size'   => 100,
]);

Geldige filter-keys volgen de GET /shipments-endpointparameters in de API-referentie. De SDK zet ze 1-op-1 door.

12 · Retouren

Retour-in-de-doos (label meestuurt met originele zending)

$consignment->setReturn(true);
$collection->addConsignment($consignment);

Het label van de retour zit op pagina 2 van de PDF. Klant plakt 'm op de doos en stuurt 'm terug.

Printerless return (klant scant QR-code bij PostNL)

$consignment->setPrinterlessReturn(true);

Geen geprint label — de klant krijgt een QR-code in de portal/e-mail. Werkt alleen op carriers die het ondersteunen.

Losse retourzending genereren

Voor retouren die los staan van een bestaande zending (bv. RMA na 30 dagen):

$collection
    ->addConsignmentByConsignmentIds([$originalId], $apiKey)
    ->generateReturnConsignments(
        sendMail: true,
        modifier: function ($returnConsignment) {
            $returnConsignment->setLabelDescription('RMA-2026-7712');
        }
    );

sendMail: true triggert de standaard MyParcel-retourmail naar de ontvanger met de QR-code of label-link.

13 · Order API (Fulfilment)

Voor accounts met fulfilment-contract: in plaats van direct labels aanmaken, plaats je een order die later in de fulfilment-flow uitvalt.

use MyParcelNL\Sdk\Collection\Fulfilment\OrderCollection;
use MyParcelNL\Sdk\Model\Fulfilment\Order;
use MyParcelNL\Sdk\Model\Fulfilment\OrderLine;
use MyParcelNL\Sdk\Model\Fulfilment\Product;
use MyParcelNL\Sdk\Model\Recipient;

$order = (new Order())
    ->setExternalIdentifier('ORDER-2026-01042')
    ->setRecipient(new Recipient([
        'cc'         => 'NL',
        'person'     => 'J. de Vries',
        'street'     => 'Antwoordnummer',
        'number'     => '42',
        'postalCode' => '1012AB',
        'city'       => 'Amsterdam',
    ]))
    ->setOrderLines([
        (new OrderLine())
            ->setQuantity(2)
            ->setProduct(
                (new Product())
                    ->setSku('SKU-7712')
                    ->setName('Linnen tas, blauw')
                    ->setEan('8712345678905')
            ),
    ]);

(new OrderCollection())
    ->setApiKey($apiKey)
    ->push($order)
    ->save(); // POST /fulfilment/orders

Order notes

Markeer fulfilment-instructies of cs-notities op een order:

use MyParcelNL\Sdk\Collection\Fulfilment\OrderNotesCollection;
use MyParcelNL\Sdk\Model\Fulfilment\OrderNote;

(new OrderNotesCollection())
    ->setApiKey($apiKey)
    ->push(
        (new OrderNote())
            ->setOrderUuid($order->getUuid())
            ->setNote('Cadeaupapier toevoegen')
            ->setAuthor('webshop')
    )
    ->save(); // POST /fulfilment/orders/{id}/notes

14 · Webhooks

De SDK heeft geen webhook-server (dat is jouw applicatie), maar wel models om subscriptions te beheren. Zie Webhooks voor end-to-end voorbeelden.

// pseudo: alle bestaande subscriptions inzien
MyParcelRequest::sendRequest('GET', 'webhook_subscriptions');

Beschikbare event-types worden actueel gehouden in de API-referentie.

15 · Exceptions

Alles in MyParcelNL\Sdk\Exception\:

ExceptionHTTPWanneer
InvalidConsignmentException412Validator weigert de combinatie van velden (carrier + opties).
MissingFieldException500Verplicht veld leeg gelaten (bv. country).
ApiException502Backend-fout of geen verbinding met api.myparcel.nl.
ValidationException422API gaf veld-validatie terug die de SDK lokaal niet ving.
AccountNotActiveException403Shop is gepauzeerd / contract niet actief.
NoConsignmentFoundException404addConsignmentByConsignmentIds met onbekende ID.

Naast deze SDK-eigen exceptions kun je ook generieke PHP-exceptions terugkrijgen — InvalidArgumentException (verkeerd type doorgegeven) en BadMethodCallException (geen setter voor die key).

use MyParcelNL\Sdk\Exception\ApiException;
use MyParcelNL\Sdk\Exception\InvalidConsignmentException;

try {
    $collection->setPdfOfLabels()->downloadPdfOfLabels();
} catch (InvalidConsignmentException $e) {
    // herstelbaar — log + corrigeer consignment
} catch (ApiException $e) {
    // network/backend — retry-with-backoff of queue
}

16 · Testen tegen de SDK

De SDK gebruikt PHPUnit + Mockery in zijn eigen tests. Voor jouw integratietests:

  • Unit-niveau — mock de MyParcelCurl-helper of de hele MyParcelCollection (addConsignment is fluent → makkelijk te mocken).
  • Integratie-niveau — gebruik een sandbox-account en de echte API. Er is geen public sandbox-URL; vraag een test-shop aan via support@myparcel.nl.
  • Snapshot tests op label-bytes zijn niet stabiel — de PDF-stitching gebruikt timestamps. Test de business logica, niet de bytes.
composer require --dev mockery/mockery phpunit/phpunit
./vendor/bin/phpunit

17 · Migreren van oudere versies

Vanaf de oude MyParcel\Sdk-namespace

De pre-v8 SDK gebruikte MyParcel\Sdk\ zonder NL. Find-and-replace:

MyParcel\Sdk\   →   MyParcelNL\Sdk\

PSR-4 doet de rest — geen verdere autoload-config nodig.

Naar v10.x

Belangrijkste breaks per minor:

VersieWat veranderde
v10.7.0priority_delivery toegevoegd voor PostNL-mailbox (BBP Prio 24h). Geen breaks.
v10.6.0printDirect() op MyParcelCollection.
v10.5.0Account general settings exposed via Account-models.
v10.4.0Trunkrs als carrier (ID 16).
v10.3.xPHP 8.4 deprecation-fixes; insurance-bedragen converteren correct naar cents.
v10.x → v9setUserAgent() is deprecated — gebruik setUserAgentForProposition().

Volledige changelog: github.com/myparcelnl/sdk/blob/main/CHANGELOG.md ↗.

18 · Bijdragen en support

PR-richtlijnen: branch vanaf main, schrijf tests met Mockery (geen live HTTP), commits volgen Conventional Commits.