Developer notes
Technical reference for developers who customize Mondial Relay Pickup Points & Labels. Every operation and field below is taken from the Mondial Relay documents and the schema files saved with the tests (tests/fixtures/official: Web_Services.wsdl, ShipmentRequest.xsd, ShipmentResponse.xsd and the two sample XML files). What the documents do not state is marked UNVERIFIED; see Conformance.
Add-on identity
Section titled “Add-on identity”| Item | Value |
|---|---|
| Add-on id | kv_mondial_relay |
| Function prefix | fn_kv_mondial_relay_ |
| Language variables | kv_mondial_relay.* |
| CSS scope | .kv-mr (admin), .kv-mrp (checkout picker) |
| PHP namespace | Tygh\Addons\KvMondialRelay |
| Shipping service class | Tygh\Shippings\Services\KvMondialRelay (module kv_mondial_relay) |
| 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\Api |
The two web services: searchPoints() (API 1 WSI4_PointRelais_Recherche), track() (API 1 WSI2_TracingColisDetaille), createShipment() (API 2), download() (label address), ping(), the Security hash (security()) and the API 1 status texts |
Client\Soap |
SOAP 1.1 envelope builder and parser for API 1 (namespace http://www.mondialrelay.fr/webservice/, SOAPAction = namespace + operation) |
Client\Connect |
API 2 request document (element order of the request XSD) and response reader (DOM; reads attributes ShipmentNumber, Status) |
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 |
Config, Access |
Settings, owner mode, who may see and manage what |
Shipments |
Order -> request mapping, label storage, return label, record-before-call idempotency, unknown-result handling (adopt, confirm nothing), tracking mapping, local cancel |
Parcel |
Field normalisation: transliteration, allowed characters, length limits, phone patterns, street/house number split, grams, OrderNo, CustomerNo, Location code |
Points |
Point Relais of an order: widget addresses, search, normalise, opening hours, server-side validation, storage |
Installer, RateCalculator |
Shipping services (3) and the merchant’s own rates (the web services have no price operation) |
Idempotency |
Per-object locks (label per order, return per shipment) |
Queue, Jobs, JobException, Log |
Job queue (back-off 5 min / 15 min / 1 h / 3 h / 12 h), recurring tracking, log with masking |
Database tables
Section titled “Database tables”| Table | Purpose |
|---|---|
?:kv_mondial_relay_accounts |
Credentials per company: test_id / live_id = API 2 login, test_secret / live_secret = API 2 password (sealed), test_pass / live_pass = API 1 private key (sealed), extra (JSON) = customer id, brand and sender address per mode, last connection check |
?:kv_mondial_relay_log |
Log |
?:kv_mondial_relay_jobs |
Queue (create_label, track) |
?:kv_mondial_relay_shipments |
Labels and tracking: provider_ref = tracking_number = 8-digit shipment number, label_data (base64) + label_url, extra_docs (JSON: returnLabel, returnState), status C created / T in transit / D delivered / P problem / X cancelled in the store / W request sent, answer not stored yet / U result unknown |
?:kv_mondial_relay_points |
Chosen Point Relais per order: point_id (6 digits), address, hours, country |
Settings
Section titled “Settings”enabled, owner_mode, debug_log, log_retention_days, label_status, core_shipment, label_format (pdf / zpl), paper_format (10x15 / A4 / A5), cod_payment, weight_default, dim_length, dim_width, dim_height, ship_days, parcel_content, send_contact, cron_key, license keys. Credentials are not settings (Connection page, Accounts). Shipping method parameters (service_params): price, tiers, free_from, countries, max_weight, delivery_text.
Hooks used
Section titled “Hooks used”PHP: change_order_status_post (queues create_label at the chosen status), get_order_info (attaches the chosen point), place_order / place_suborders (store the point), delete_order, template_document_order_context_init (point in order documents), init_templater_post (only while an in-place upgrade is pending). Pre-controller checkout.pre (a Point Relais order cannot be placed without a point) and post-controller orders.post (order tab data).
Templates: backend orders:tabs_extra (order tab), addons:manage, addons:tabs_content (license card), index:styles; storefront checkout:shipping_method (picker card), orders:totals_shipping (point on the order page), index:scripts, index:styles. The picker is an AJAX POST only (kv_mondial_relay.point_select) and the widget is loaded by JavaScript when the customer opens the panel, so no cacheable page contains Mondial Relay data.
How to extend
Section titled “How to extend”- Another service. Add the code to
Installer::services(), its delivery mode toInstaller::product()and, if it is a Point Relais service, toInstaller::isPickup()andPoints::action(). A service with a delivery mode that needs an extra step (for example XOH) must not be added without that step. - Rates. The rate logic is
RateCalculator::quote()/price(); replace the table with your own logic there. - Fields of the shipment request.
Shipments::payload()builds the data array,Client\Connect::request()writes the XML in the order of the request XSD. Add new elements in the XSD sequence position; the unit tests validate every request against the XSD. - Options (
LNG,ASS) andshipmentValueare not sent; see the notes inClient\Connect.
Test without Mondial Relay
Section titled “Test without Mondial Relay”The base URL can be overridden for tests in config.local.php (development only; production always uses the Mondial Relay HTTPS hosts):
$config['kv_mondial_relay_base_url'] = 'http://127.0.0.1:11853';php -S 127.0.0.1:11853 tests/mock-server/server.php starts a local stand-in that validates API 2 requests against the official request XSD and the documented field patterns, validates API 1 requests against the WSDL types, checks the Security hash with the documented algorithm (test account BDTEST13), and serves a stand-in of the widget with the same plugin name and callback (it draws no map). node tests/e2e/e2e.mjs runs the HTTP end-to-end test against it; php tests/unit.php runs the unit tests. This proves the add-on against the documents and a mock, not against Mondial Relay: no call to the sandbox or to the live service was made.
Template overrides
Section titled “Template overrides”Admin templates live in design/backend/templates/addons/kv_mondial_relay/, storefront templates in var/themes_repository/responsive/templates/addons/kv_mondial_relay/. Do not edit them in a store; they are replaced on update.
Provider operations and fields
Section titled “Provider operations and fields”Sources: [DC] WEB SERVICE DUAL CARRIER V-2.7.1 (June 2024; page numbers from its contents); [WS] WEB SERVICE V-5.14 (January 2025); [W] WIDGET V4.1 (December 2019); [P] Presentation of WebServices V-1.1 (April 2025); [XSD-Q] Mondial-Relay-Shipment-API-.Request.1.0.xsd; [XSD-R] the matching Response.1.0.xsd; [WSDL] Web_Services.wsdl.
Operation overview
Section titled “Operation overview”| Operation | Endpoint | Source |
|---|---|---|
API 2 ShipmentCreationRequest (labels, outbound and return) |
POST https://connect-api-sandbox.mondialrelay.com/api/shipment (test), https://connect-api.mondialrelay.com/api/shipment (live). Headers Accept: application/xml, Content-Type: text/xml, body UTF-8 without BOM |
[DC] “Service overview” p. 9, “Service request specifications” p. 18 |
API 1 WSI4_PointRelais_Recherche |
POST https://api.mondialrelay.com/Web_Services.asmx (SOAP 1.1) |
[WS] “General description” p. 6, “Point Relais search” p. 9-13; [WSDL] |
API 1 WSI2_TracingColisDetaille |
same | [WS] “Parcel tracking” p. 26; [WSDL] |
Widget MR_ParcelShopPicker |
script https://widget.mondialrelay.com/parcelshop-picker/jquery.plugin.mondialrelay.parcelshoppicker.min.js loaded in the customer’s browser |
[W] “Utilisation” p. 5 |
| Label download | GET of the address in Label/Output (PdfUrl), only on mondialrelay.* hosts, https |
[DC] “Output entity” p. 19-20 |
Not used: API 1 WSI2_CreationExpedition, WSI2_CreationEtiquette, WSI3_GetEtiquettes ([WS] V-5.11: stopped; “Accounts created from 23/12/2024 will be blocked for the shipment creation with this API”), WSI2_RechercheCP, WSI2_STAT_Label.
API 2 request: ShipmentCreationRequest (namespace http://www.example.org/Request)
Section titled “API 2 request: ShipmentCreationRequest (namespace http://www.example.org/Request)”| Element / attribute | Type, limit, pattern (document) | How the add-on fills it | Source |
|---|---|---|---|
Context/Login |
String, mandatory | API 2 login of the Connection page | [DC] p. 11, [XSD-Q] |
Context/Password |
String, mandatory | API 2 password (never logged) | [DC] p. 11 |
Context/CustomerId |
String, mandatory, max 8, ^[0-9A-Z]{2}[0-9A-Z]{6}$ |
Customer id of the Connection page. The form accepts 2 to 8 letters and digits (looser than the document pattern) | [DC] p. 11, [XSD-Q] |
Context/Culture |
String, mandatory, 5, ^[a-z]{2}-[A-Z]{2}$ |
Fixed fr-FR (as in every example) |
[DC] p. 11 |
Context/VersionAPI |
Enumeration, mandatory | Fixed 1.0 (“Version that match this document is 1.0”) |
[DC] p. 11 |
OutputOptions/OutputFormat |
Enumeration. PdfUrl: 10x15, A4, A5; ZplCode: Generic_ZPL_10x15_200dpi; IplCode: Generic_IPL_10x15_204dpi |
Setting “Label size” (10x15, A4, A5) or Generic_ZPL_10x15_200dpi |
[DC] p. 12 |
OutputOptions/OutputType |
Enumeration: ZplCode, PdfUrl, IplCode |
PdfUrl or ZplCode. IplCode, the Monarch printer models and QRCode are not offered |
[DC] p. 12 |
ShipmentsList/Shipment/Options |
Option Key (ASS, LNG) / Value, optional, “not for returns” |
Not sent | [DC] p. 13, 17 |
Shipment/OrderNo |
String, optional, max 15, ^(|[0-9A-Z_ -]{0,15})$ |
O<order id>-<shipment row id> (return: R...), cut at 15 characters. Deterministic: the reference to look for in Connect after an unknown result |
[DC] p. 13 |
Shipment/CustomerNo |
String, optional, max 9, ^(|[0-9A-Z]{0,9})$ |
K<order id>, cut at 9 characters |
[DC] p. 13 |
Shipment/ParcelCount |
Integer, mandatory, ^[0-9]{1,2}$; multi-parcel only for 24L, LD1, LDS |
Always 1 |
[DC] p. 13 |
Shipment/ShipmentValue (shipmentValue.amount, .currency) |
Float / EUR, optional in the PDF |
Not sent. The XSD marks it required and its currency list is a placeholder (value); only the ASS option needs it. See Conformance |
[DC] p. 13, [XSD-Q] |
Shipment/DeliveryMode@Mode |
String, mandatory, 3, ^[0-9A-Z]{3}$ |
24R, 24L, HOM; return label: LCC |
[DC] p. 13-14 |
Shipment/DeliveryMode@Location |
String, optional, max 10, ^[0-9A-Z]{0,10}$, mandatory for 24R, 24L, XOH |
24R/24L: <country>-<point number without leading zeros> (for example FR-66974); HOM and LCC: empty. UNVERIFIED against the live service: the examples show FR-66974 for the point the widget calls 066974; the XSD comment shows FR00001 |
[DC] p. 13, example p. 27, [XSD-Q] |
Shipment/CollectionMode@Mode |
String, mandatory, 3 | CCC (merchant collection); return label: REL |
[DC] p. 14 |
Shipment/CollectionMode@Location |
String, optional, default “Auto” | outbound: empty; return: Auto |
[DC] p. 13 |
Parcels/Parcel/Content |
String, optional, max 40, ^[0-9A-Z_\-'., /]{0,40}$ |
Setting “Parcel content text”, cleaned and cut at 40; omitted when empty | [DC] p. 14 |
Parcel/Length, Width, Depth (Value, Unit="cm") |
Integer, optional (mandatory for Poland), max 10 | From the package size settings when greater than 0 and below 1000; otherwise omitted | [DC] p. 14, [XSD-Q] |
Parcel/Weight (Value, Unit="gr") |
Integer, mandatory, ^[0-9]{0,10}$, “Minimum 10grs” |
Sum of product weight x quantity in grams (weight unit of the store taken into account), at least 10; the setting “Default parcel weight” when no product has a weight | [DC] p. 14 |
Shipment/DeliveryInstruction |
String, optional, max 30 | Not sent | [DC] p. 14 |
Sender/Address, Recipient/Address |
AddressType, XSD order: Title, Firstname, Lastname, Streetname, HouseNo, CountryCode, PostCode, City, AddressAdd1, AddressAdd2, AddressAdd3, PhoneNo, MobileNo, Email. Empty elements are omitted |
Outbound: sender = Connection page (or company data), recipient = delivery address of the order. Return: swapped ([P] section 4: the sender is the end customer, the recipient the return address) | [DC] p. 15-17, [XSD-Q] |
Address/Title |
String, optional | Not sent | [DC] p. 15 |
Address/Firstname, Lastname |
Max 32 each / 40 together in the table (XSD: 30 each); error 10062: Title + first + last name max 30 | Cleaned; together at most 30 characters (first name cut to 12 when needed) | [DC] p. 15, error 10062 |
Address/Streetname + HouseNo |
Street max 40, house number max 10; error 10063: HouseNo + StreetName max 30; Netherlands: the number goes at the end of the street field | Street line split into street and number; together at most 30 characters (overflow goes to AddressAdd3); NL: the number is appended to the street |
[DC] p. 15, error 10063 |
Address/CountryCode |
^[A-Z]{2}$ |
ISO 3166-1 alpha-2 of the order address (Monaco is handled by Mondial Relay as FR) | [DC] p. 15, [WS] p. 5 |
Address/PostCode |
Max 10 | Cleaned, cut at 10 | [DC] p. 15 |
Address/City |
Max 30 | Cleaned, cut at 30 | [DC] p. 15 |
Address/AddressAdd1 |
Max 30. “Name. Do not fill it if Firstname/Lastname are filled” | Company name only when no first and last name exist | [DC] p. 16 |
Address/AddressAdd2 |
Max 30, additional name | Company name when a person name exists | [DC] p. 16 |
Address/AddressAdd3 |
Max 30, additional address information | Street overflow and the second address line | [DC] p. 16 |
Address/PhoneNo, MobileNo |
Max 20, pattern per country (“Regular expression for phone numbers”); XSD \+\d{3,20}; PhoneNo mandatory for home delivery |
Normalised to +<dialing code><number> and checked against the country table of the document (FR, ES, BE, DE, LU, PT, AT, UK, IT, NL, IE, MC, CH, PL); a mobile prefix goes to MobileNo, otherwise PhoneNo. Recipient: always for home delivery (outbound), otherwise only with “Send e-mail address and mobile number”. Sender: from the Connection page |
[DC] p. 16-17 |
Address/Email |
Max 70, ^[\w\-\.\@_]{7,70}$ |
Recipient: only with the privacy setting on; sender: the merchant’s own | [DC] p. 16 |
API 2 response: ShipmentCreationResponse (namespace http://www.example.org/Response)
Section titled “API 2 response: ShipmentCreationResponse (namespace http://www.example.org/Response)”| Element / attribute | Use | Source |
|---|---|---|
ShipmentsList/Shipment@ShipmentNumber |
The 8-digit shipment number: stored as provider_ref and tracking number. Present in the PDF example, not declared in the response XSD (UNVERIFIED if the live service always sends it); an answer without a valid 8-digit number is parked as “result unknown” |
[DC] p. 28, [XSD-R] |
Shipment/LabelList/Label/Output |
PdfUrl: an address to fetch the PDF from; ZplCode: base64 ZPL. Fetched immediately (PDF) and stored | [DC] p. 19-20, example p. 29 |
Label/RawContent/Barcodes/Barcode (Type, DisplayedValue, Value, CarrierCode) |
Read by the parser, not stored (the barcode is part of the label) | [DC] p. 19, [XSD-R] |
Label/RawContent/LabelValues (Key, Value) |
Read by the parser, not stored | [DC] example p. 29, [XSD-R] |
StatusList/Status (Code, Level, Message) |
Level “Warning” is logged and does not stop the label; any other level (“Error”, “Critical Error”) is a rejection with the code and message; codes -1 and 99999 count as an unknown outcome |
[DC] p. 21-26 |
| HTTP status | 5xx, 408, 425, 429 and network errors are technical errors (“the user of the service can try to call the service later again”); 425 and 429 are treated as rejections, the others as unknown outcome | [DC] p. 22 |
Raw content other than the above (Sender, Recipient, Parcel, RoutingArguments) is not used.
API 1 WSI4_PointRelais_Recherche (SOAP, namespace http://www.mondialrelay.fr/webservice/)
Section titled “API 1 WSI4_PointRelais_Recherche (SOAP, namespace http://www.mondialrelay.fr/webservice/)”The 16 SOAP parameters in WSDL order are listed below with the documented Security order. Security = upper case MD5 of the concatenation of the parameter values in documentation order (empty values add nothing) followed by the private key: [Enseigne][Pays][NumPointRelais][Ville][CP][Latitude][Longitude][Taille][Poids][Action][DelaiEnvoi][RayonRecherche][TypeActivite][NombreResultats][CLE PRIVEE] ([WS] “Generating the security key” p. 7 and the parameter table within p. 9-13). NACE is in the WSDL between TypeActivite and NombreResultats (“Non applicable”) and is sent empty; it is not part of the Security string.
| # | Parameter | Document (type, pattern) | How the add-on fills it |
|---|---|---|---|
| 1 | Enseigne |
O, 8, ^[0-9A-Z]{2}[0-9A-Z ]{6}$ |
Brand of the Connection page |
| 2 | Pays |
O, ^[A-Za-z]{2}$ |
Country of the delivery address (checkout validation: country of the cart) |
| 3 | NumPointRelais |
F/O, ^[0-9]{6}$, with Pays for one point |
The 6-digit point number when validating the customer’s choice; empty otherwise |
| 4 | Ville |
F/O, “NON APPLICABLE” | Empty |
| 5 | CP |
F/O, depends on the country | Postal code of the search (the point’s postal code for the XL check) |
| 6 | Latitude |
F/O, ^-?[0-9]{2}\.[0-9]{7}$ |
Empty |
| 7 | Longitude |
F/O | Empty |
| 8 | Taille |
F, “Do not use unless specified by Mondial Relay” | Empty |
| 9 | Poids |
F, grams, ^[0-9]{1,6}$, 15 g minimum |
Sent only when a weight of at least 15 g is given |
| 10 | Action |
F, ^(SMA|APM|REL|MED|24R|24L|XOH)$ |
24R or 24L by the shipping method |
| 11 | DelaiEnvoi |
F, ^-?[0-9]{2})$ |
Setting “Days between the order and the hand-over” as two digits, only when above 0 |
| 12 | RayonRecherche |
F, ^[0-9]{1,4}$, default 50 km, 0 = no filter |
Empty (default 50 km) |
| 13 | TypeActivite |
F, ^(\d{3},|\d{3})*$ |
Empty |
| 14 | NACE |
NA | Empty (not in the Security string) |
| 15 | NombreResultats |
O, max 30 | 1 to 30 (1 for one point, 30 for the XL check, 1 for the connection test) |
| 16 | Security |
O, ^[0-9A-Z]{32}$ |
As above |
Response used: WSI4_PointRelais_RechercheResult: STAT (0 = success; any other value is an error with the text of the status table), PointsRelais/PointRelais_Details: Num (6 digits), LgAdr1 + LgAdr2 (name), LgAdr3 + LgAdr4 (address), CP, Ville, Pays, Latitude, Longitude (the widget sample uses a decimal comma, converted), Distance (meters per [WS]; stored, not shown), Horaires_Lundi … Horaires_Dimanche (string array of 4: opening and closing time of slot 1, opening and closing time of slot 2). Not used: Localisation1/2, TypeActivite, NACE, Information, Informations_Dispo, URL_Photo, URL_Plan. The document names Lgdr1 and Horaire_ Lundi; the WSDL names LgAdr1 and Horaires_Lundi; the add-on follows the WSDL. The format of the opening-hour strings is UNVERIFIED (the WSDL says ArrayOfString): HHMM is assumed, HH:MM is accepted, 0000 means none.
API 1 WSI2_TracingColisDetaille
Section titled “API 1 WSI2_TracingColisDetaille”| Parameter | Document | How the add-on fills it |
|---|---|---|
Enseigne |
O, 8, ^[0-9A-Z]{2}[0-9A-Z ]{6}$ |
Brand |
Expedition |
O, ^[0-9]{8}$ |
The 8-digit shipment number |
Langue |
O, ^[A-Z]{2}$, “Language requested for tracking” |
Fixed FR. The supported languages are UNVERIFIED |
Security |
O, ^[0-9A-Z]{32}$, string [Enseigne][Expedition][Langue][CLE PRIVEE] |
As above |
Response used: STAT (accepted: 0, 80 recorded parcel, 81 parcel in process at Mondial Relay, 82 delivered parcel, 83 anomaly; 94 unknown parcel keeps the stored status; every other value is an error), Libelle01, and Tracing/ret_WSI2_sub_TracingColisDetaille rows with Libelle, Date, Heure, Emplacement (the document names them Tracing_Libelle, Tracing_Date, Tracing_Heure, Tracing_Lieu; the WSDL names are used). The latest row becomes the status text; the rows (newest first) are the event history. [WS] p. 26: “the API return the 5 biggest steps”; [P] section 3: at most 4 to 6 queries per shipment and day, no batch use, completed shipments are not queried again.
Widget MR_ParcelShopPicker options
Section titled “Widget MR_ParcelShopPicker options”| Option | Document | Value used |
|---|---|---|
Target |
Yes, jQuery selector that receives the point ID | A hidden element of the picker panel |
Brand |
Yes, customer code, 8 characters padded with spaces on the right | Brand of the Connection page padded to 8 characters |
Country |
No, default FR | Country of the delivery address (default FR) |
AllowedCountries |
No, ISO codes separated by commas | The same country only (the point must be in the delivery country, status 92) |
ColLivMod |
No, default 24R (L), 24L (XL) | 24R or 24L by the shipping method |
NbResults |
No, default 7 | "7" |
Responsive |
No, default false | true |
ShowResultsOnMap |
No, default true | true |
DisplayMapInfo |
No, default true | true |
PostCode |
No, postal code for a default search | Postal code of the delivery address |
SearchDelay |
No, days between search and drop-off | Setting “Days between the order and the hand-over”, only when above 0 |
OnParcelShopSelected |
Callback, data object with ID, Nom, Adresse1, Adresse2, CP, Ville, Pays, Lat, Long |
Only data.ID (6 digits, for example 066974) is read and posted to kv_mondial_relay.point_select; the server looks the point up again and stores its own answer |
Method MR_RebindMap |
Re-draws the map of a widget started in a hidden panel | Triggered after the widget starts |
Not used: TargetDisplay, TargetDisplayInfoPR, EnableGeolocalisatedSearch, Weight, CSS, MapScrollWheel, MapStreetView, EnableGmap, OnNoResultReturned, OnSearchSuccess, methods MR_SetParams, MR_DoSearch. The document asks the page to load jQuery 2.2.4 and an unversioned Leaflet from unpkg; the add-on uses the jQuery of the store and Leaflet 1.9.4 from unpkg.com; compatibility of the widget with that jQuery and Leaflet version is UNVERIFIED. The brand BDTEST (test) makes the widget show a warning ([W] p. 13).