Developer notes
Technical reference for developers who customize DPD Shipping Labels & Pickup Points. Every operation and field below is taken from the official WSDL / XSD files saved in tests/fixtures/wsdl (downloaded from the DPD stage system, 7 November 2026). What the documentation does not state is marked unverified; see Conformance.
Add-on identity
Section titled “Add-on identity”| Item | Value |
|---|---|
| Add-on id | kv_dpd |
| Function prefix | fn_kv_dpd_ |
| Language variables | kv_dpd.* |
| CSS scope | .kv-dpd, .kv-dpdp (checkout picker) |
| PHP namespace | Tygh\Addons\KvDpd |
| Preset | shipping (generated by kv new --kind integration) |
Structure
Section titled “Structure”| Class | Role |
|---|---|
Client\BaseClient |
HTTP (cURL, TLS verification, timeouts), error mapping (decodeError hook), masked logging |
Client\Soap |
SOAP 1.1 envelope builder (ordered arrays, schema order) and parser (namespace prefixes removed, repeated elements as lists), fault decoding |
Client\Api |
The five services: token() (LoginService), storeOrders(), findParcelShops(), findByGeo(), track(), ping() |
Client |
Client per company, the connection test |
Accounts, Secret |
Credentials (test and live) sealed with AES-256-GCM; one account per store owner or per vendor; token cache with the depot of the login |
Config, Access |
Settings, owner mode, who may see and manage what |
Shipments |
Payload mapping order -> storeOrders, label storage, return label, tracking mapping, local cancel |
Points |
Parcel shop of an order: search, normalise, validate, store |
Installer, RateCalculator |
Shipping services (7) and the merchant’s own rates (the web services have no price operation) |
Queue, Jobs, JobException, Log |
Job queue (back-off 5 min / 15 min / 1 h / 3 h / 12 h), recurring tracking, log |
SOAP operations
Section titled “SOAP operations”All calls are POST <services root>/<Service>/<Version> with Content-Type: text/xml; charset=utf-8 and SOAPAction: "http://dpd.com/common/service/<Service>/<major.minor>/<operation>". Body elements are in the namespace http://dpd.com/common/service/types/<Service>/<major.minor>; children are unqualified. The header authentication is in http://dpd.com/common/service/types/Authentication/2.0.
| Operation | Request fields used | Response fields used |
|---|---|---|
LoginService/V2_0 getAuth |
delisId, password, messageLanguage (en_US) |
return.authToken (max 64), return.depot, return.customerUid, return.delisId |
ShipmentService/V4_5 storeOrders |
printOptions.printOption(outputFormat, paperFormat); order.generalShipmentData(mpsCustomerReferenceNumber1, identificationNumber, sendingDepot, product, mpsWeight, mpsExpectedSendingDate, sender, recipient, softwareVersion); order.parcels(customerReferenceNumber1, volume, weight, returns); order.productAndServiceData(orderType, parcelShopDelivery(parcelShopId, parcelShopPudoId, parcelShopNotification(channel, value, language)), predict(channel, value, language), international(parcelType, customsAmount, customsCurrency, customsInvoice, customsInvoiceDate, numberOfArticle, reasonForExport, additionalInvoiceLines(customsInvoicePosition, quantityItems, customsContent, customsAmountLine, customsOriginAlphanumeric, customsGrossWeight))); addresses: name1, name2, street, houseNo, state, country, zipCode, city, customerNumber, contact, phone, email, addressType, additionalInfo2 |
orderResult.output(format, content), shipmentResponses(identificationNumber, mpsId, parcelInformation(parcelLabelNumber, dpdReference, output(format, content)), faults(faultCode, message)) |
ParcelShopFinderService/V5_0 findParcelShops |
country, zipCode, city, street, limit, availabilityDate, hideClosed |
parcelShop(parcelShopId, pudoId, company, street, houseNo, country, zipCode, city, latitude, longitude, openingHours(weekday, openMorning, closeMorning, openAfternoon, closeAfternoon)) |
ParcelShopFinderService/V5_0 getAvailableServices |
none (connection test) | services |
ParcelShopFinderService/V5_0 findParcelShopsByGeoData |
longitude, latitude, limit (Api::findByGeo, not used by the checkout) |
as findParcelShops |
ParcelLifeCycleService/V2_0 getTrackingData |
parcelLabelNumber |
trackingresult.statusInfo(status, label, location, date, statusHasBeenReached, isCurrentStatus, normalItems, importantItems, errorItems), shipmentInfo |
SOAP faults (HTTP 500) are decoded from detail: authenticationFault(errorCode -1 | -2, errorMessage), LoginException(errorCode, message), dataFault / systemFault(errorCode, message). The exact fault encoding is read from the XSD; no fault was captured from the real service (unverified). An authentication fault leads to one new login and one repeat of the call.
Mapping notes
Section titled “Mapping notes”| Topic | Rule |
|---|---|
| Products | dpd_classic and dpd_pickup -> CL; dpd_830 -> E830; dpd_1200 -> E12; dpd_1800 -> E18; dpd_max -> MAX; dpd_express -> IE2 |
| Weight | Parcel::units() = kg x 100 (units of 10 g, per the example “300 equals 3kg”); unverified, see Conformance |
| Volume | Parcel::volume() = LLLWWWHHH, minimum 1001001 |
| Money | Parcel::cents() = amount x 100 without separator (customsAmount, customsAmountLine), invoice currency EUR |
| Element order | XSD sequences are ordered: Parcel::sortAddress() orders the address fields; the payload arrays are written in schema order. The unit tests validate every request against the XSD |
| Cash on delivery | no field exists since 4.4: refused, never sent |
| Cancel | no operation exists: local only |
Database tables
Section titled “Database tables”| Table | Purpose |
|---|---|
?:kv_dpd_accounts |
Credentials per company (password sealed), last connection check, token cache (with depot) |
?:kv_dpd_log |
Log |
?:kv_dpd_jobs |
Queue |
?:kv_dpd_shipments |
Labels and tracking (provider_ref and tracking_number = parcel label number, courier_number = mpsId, extra_docs = return label) |
?:kv_dpd_points |
Parcel shop per order (carrier_id = parcelShopId, point_id = pudoId) |
Hooks used
Section titled “Hooks used”PHP: change_order_status_post (label at status), get_order_info (attaches the parcel shop), place_order / place_suborders (store the shop), delete_order, template_document_order_context_init (shop in order documents). Templates: backend orders:tabs_extra, addons:manage, addons:tabs_content, index:styles; storefront checkout:shipping_method (picker), orders:totals_shipping (shop on the order page), index:scripts, index:styles. The picker is an AJAX POST only (kv_dpd.locations, kv_dpd.point_select) and never cached, so the full page cache stays safe.
Test without DPD
Section titled “Test without DPD”The base URL can be overridden for tests in config.local.php (development only; the add-on appends /services):
$config['kv_dpd_base_url'] = 'http://127.0.0.1:11852';php -S 127.0.0.1:11852 tests/mock-server/server.php starts a local stand-in that validates every request against the official XSD files; node tests/e2e/e2e.mjs runs the HTTP end-to-end test against it; php tests/unit.php runs the unit tests (also on php81 and php83). This proves the add-on against the specification, not against DPD.
Template overrides
Section titled “Template overrides”Admin templates live in design/backend/templates/addons/kv_dpd/. Do not edit them in a store; they are replaced on update.