Shipping API Spec V2 - Parcelforce  · Web viewRoyal Mail Shipping API V2 exposes a web service...

23
API Sample Code Royal Mail Group Shipping API V2 (SOAP) Sample Code User Guide This user guide provides sample PHP code for customers wishing to integrate with Shipping API V2 (SOAP) to help accelerate their customer onboarding. This document must be read in conjunction with the accompanying API specification for Shipping API V2 (SOAP) and which is available on the Royal Mail API (Developer) Portal . 11 th July 2016 Version 1.0 Page 1 of 23

Transcript of Shipping API Spec V2 - Parcelforce  · Web viewRoyal Mail Shipping API V2 exposes a web service...

AP

I

Sa

mp

le

C

od

e Royal Mail Group

Shipping API V2 (SOAP)Sample Code User Guide

This user guide provides sample PHP code for customers wishing to integrate with Shipping API V2 (SOAP) to help accelerate their customer onboarding. This document must be read in conjunction with the accompanying API specification for Shipping API V2 (SOAP) and which is available on the Royal Mail API (Developer) Portal .

11th July 2016 Version 1.0

Page 1 of 19

Page 2 of 19

Contents1 Document Control................................................................3

1.1 Terms and Abbreviations.................................................................31.2 Version History................................................................................3

2 Overview.............................................................................43 Purpose...............................................................................54 Terms and Conditions...........................................................65 Sample Code for createShipmentRequest..............................7

5.1 PHP cURL.........................................................................................75.1.1 Sample Code..............................................................................75.1.2 Code Variables.........................................................................10

5.2 PHP HTTP (PHP with SOAP Client)..................................................115.2.1 Sample Code (Request)...........................................................115.2.2 Code Variables.........................................................................145.2.3 Response.................................................................................14

5.3 Testing Framework........................................................................17

Page 3 of 19

1 Document Control1.1 Terms and AbbreviationsTerm MeaningBase64 A standard binary-to-text encoding scheme that is used to

represent binary data in an ASCII string format. Used to include binary data with an XML structure

HTTPS Hypertext Transfer Protocol over SSLNonce User generated random string that is used as part of the

password hashing process to ensure that messages cannot be replayed

SOAP Originally an acronym for Simple Object Access Protocol, is a protocol specification for exchanging structured information in the implementation of web services

WSDL Web Service Description LanguageXSD XSD is XML Schema Definition – this defines a specific

template for the XML used by particular systemsXML eXtensible Markup Language, a flexible standard for data

inside a hierarchical structure of named data itemsTable 1 – Terms and Abbreviations

1.2 Version HistoryVersio

nDate Notes

0.1 30/06/2016 Baseline document created with sample PHP code provided to assist customer integration with Shipping API V2.

1.0 11/07/2016 Document updated and baselined following internal feedback.

Table 2 – Document Version History

Page 4 of 19

2 OverviewRoyal Mail Shipping API V2 exposes a web service that allows account customers to create shipments, produce labels, and produce documentation for all the tasks required to ship items with Royal Mail. Built on industry standards, Shipping API V2 provides a simple and low cost method for customers to integrate with Royal Mail and allows them to get shipping quickly.There are no costs to customers for using the Shipping API V2 services, however customers’ own development costs must be covered by the customer developing the solution. Royal Mail will not accept any responsibility for these development, implementation and testing costs.

Page 5 of 19

3 PurposeThis document provides Royal Mail customers with sample PHP code to accelerate integration and onboarding activities with the Shipping API V2 SOAP web service. The document details:

The sample code for creation of password digest in PHP The sample code for a domestic createShipment web service

interface Details of the variables or elements in the sample code which must

be changed by the customer when integrating their application with Shipping API V2

This document is primarily intended to be used by developers and other technical roles involved with integrating customer systems’ with Shipping API. This document should be read in conjunction with the following artefacts which are available from the Shipping API V2 page on the Royal Mail API (Developer) Portal:

Shipping API V2 Technical User Guide Shipping API V2 WSDL Shipping API V2 XSDs Shipping API V2 Reference Data Shipping API V2 FAQ

This document provides the PHP sample code for the following Shipping API operation:

createShipment

It is expected that the customer will adapt and extend the code provided to call the following API operations to meet their business needs:

updateShipment cancelShipment printLabel createManifest printManifest printDocument request1DRangesRequest request2DItemIDRangeRequest

Page 6 of 19

4 Terms and Conditions1. The sample code is provided to help accelerate the integration and

onboarding process. For this reason it shouldn’t be considered as final code. Customers are expected to make changes to the code (e.g. to provide the required technical and business data to fulfil the API operation) and integrate this with their own system(s).

2. The sample code in this document is provided ‘as-is’ without any warranty of any kind, either expressed or implied, including, but not limited to, the implied merchantability and fitness for a particular purpose. The risk as to the quality and performance of the code lies with the customer. Should the code prove to be defective in any way, the customer will assume the cost of all necessary servicing, repair or correction.

3. In no event shall the authors or Royal Mail be liable for any claim, damages or any other liability whether in an action of contract, tort or otherwise, arising from the use of or other dealings with the provided software.

4. Please see the generic Terms and Conditions associated with the use of the Royal Mail API services and sample code on the API (Developer) Portal.

Page 7 of 19

5 Sample Code for createShipmentRequestThis section provides sample code for a createShipment request message for a domestic shipment and is provided for example / illustrative purposes only. Please note that the sample code as provided requires adaptation by the customer in order to fully integrate it with their system and provide the required data for the shipment being requested and in accordance with the Shipping API V2 specification. The variables in the example code have been highlighted in yellow for visibility. It is recommended that the customer view the code in a software development toolkit for ease of readability.Please read the Technical User Guide available on the Shipping API V2 page of the Royal Mail API (Developer) Portal for details of the API message structure and elements required to use a particular Shipping API operation.Sample code is provided in the subsequent sections for the following languages:

PHP cURL PHP HTTP (PHP with SOAP Client)

5.1 PHP cURLThe sample code provided in this section is compatible with PHP versions 5 through to 7.

5.1.1Sample Code<?php/*------------------------------------------------------------------------------------------------------------------ *//* This code has been written as a sample to demonstrate how the API call can be *//* made using PHP cURL. The code also shows the auto generation of *//* password digest, encoded nonce and time when these values are created *//* can be calculated, to populate the WS-security header of the SAPI SOAP service. *//* The security header for the SAPI service needs to provide, *//* Username as - <wsse:Username>YOURUSENAME</wsse:Username> *//* where YOURUSENAME is the username provided by RMG *//* Password as - <wsse:Password Type="http://d...content-available-to-author-only...n.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">PASSWORDDIGEST</wsse:Password> *//* where PASSWORDDIGEST is calculated as shown in the code below *//* Nonce as - <wsse:Nonce EncodingType="http://d...content-available-to-author-only...n.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">ENCODEDNONCE</wsse:Nonce> *//* where ENCODEDNONCE is shown in the code below *//* Creation date - <wsu:Created>CREATIONDATE</wsu:Created> *//* where CREATIONDATE is shown in the code below *//* *//* To make a successful API call by using the code below, one must: *//* a) Provide the right username *//* a) Change the password to your password *//*-------------------------------------------------------------------------------------------------------------------*/

$apiURL = "https://api.royalmail.net/shipping/v2";$dateTime = date('Y-m-d\TH:i:s');$applicationId = "xxx";

Page 8 of 19

$transactionId = "xx";$shippingDate = gmdate('Y-m-d');$shipmentType = "Delivery";$serviceOccurrence = "x";$serviceType = "x";$serviceCode = "xx";$serviceFormat = "x";$recipientContactName = "Tom Smith";$recipientAddressLine1 = "3 Bowerman Close";$postTown = "London";$postcode = "OX5 1TP";$countryCode = "GB";$noOfItems = "1";$unitOfMeasure = "g";$weightValue = "100";$sendersReference = "123ABC";

/* Change the values below to the ClientID and Secret values associated with the application you * registered on the API Developer Portal */$clientId = "xxx";$clientSecret = "xxx";

/* The value below should be changed to your actual username and password. If you store the password * as hashed in your database, you will need to change the code below to remove hashing */ $username = "xxx";$password = “Password1*”;

/* CREATIONDATE - The timestamp. The computer must be on correct time or the server you are* connecting may reject the password digest for security.*/$creationDate = gmdate('Y-m-d\TH:i:s\Z');

/* NONCE - A random word. * The use of rand() may repeat the word if the server is very loaded.*/$nonce = mt_rand();

/* PASSWORDDIGEST This is the way to create the password digest. As per OASIS standard* digest = base64_encode(Sha1(nonce + creationdate + Sha1(password)))* Note that we use a Sha1(password) instead of the plain password above*/$nonce_date_pwd = $nonce.$creationDate.base64_encode(sha1($password, TRUE));$passwordDigest = base64_encode(sha1($nonce_date_pwd, TRUE)); /* ENCODEDNONCE - Now encode the nonce for security header */$encodedNonce = base64_encode($nonce);

/* Print all WS-Security values for debugging * echo 'nonce: ' . $nonce . PHP_EOL; * echo 'password digest: ' . $passwordDigest . PHP_EOL; * echo 'encoded nonce: ' . $encodedNonce . PHP_EOL; * echo 'creation date: ' . $creationDate . PHP_EOL; */

$curl = curl_init();

/* The commented code below is provided for customers to adapt to handle the client side security * implementation for the API * * PHP code to validate the certificate returned from APIm * CURLOPT_SSL_VERIFYHOST can be set to the following integer values:

Page 9 of 19

* 0: Dont check the common name (CN) attribute * 1: Check that the common name attribute at least exists * 2: Check that the common name exists and that it matches the host name of the server */// curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);// curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);// curl_setopt($curl, CURLOPT_CAINFO, getcwd() . "\(path)\api.royalmail.net.crt");

curl_setopt_array($curl, array( CURLOPT_URL => $apiURL, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST",

CURLOPT_POSTFIELDS => "<soapenv:Envelope xmlns:oas=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:v1=\"http://www.royalmailgroup.com/integration/core/V1\" xmlns:v2=\"http://www.royalmailgroup.com/api/ship/V2\">\r\n <soapenv:Header>\r\n <wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">\r\n <wsse:UsernameToken>\r\n <wsse:Username>$username</wsse:Username>\r\n <wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">$passwordDigest</wsse:Password>\r\n <wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">$encodedNonce</wsse:Nonce>\r\n <wsu:Created>$creationDate</wsu:Created>\r\n </wsse:UsernameToken>\r\n </wsse:Security>\r\n </soapenv:Header>\r\n <soapenv:Body>\r\n <v2:createShipmentRequest>\r\n <v2:integrationHeader>\r\n <v1:dateTime>$dateTime</v1:dateTime>\r\n <v1:version>2</v1:version>\r\n <v1:identification>\r\n <v1:applicationId>$applicationId</v1:applicationId>\r\n <v1:transactionId>$transactionId</v1:transactionId>\r\n </v1:identification>\r\n </v2:integrationHeader>\r\n <v2:requestedShipment>\r\n <v2:shipmentType>\r\n <code>$shipmentType</code>\r\n </v2:shipmentType>\r\n <v2:serviceOccurrence>$serviceOccurrence</v2:serviceOccurrence>\r\n <v2:serviceType>\r\n <code>$serviceType</code>\r\n </v2:serviceType>\r\n <v2:serviceOffering>\r\n <serviceOfferingCode>\r\n <code>$serviceCode</code>\r\n </serviceOfferingCode>\r\n </v2:serviceOffering>\r\n <v2:serviceFormat>\r\n <serviceFormatCode>\r\n <code>$serviceFormat</code>\r\n </serviceFormatCode>\r\n </v2:serviceFormat>\r\n <v2:shippingDate>$shippingDate</v2:shippingDate>\r\n <v2:recipientContact>\r\n <v2:name>$recipientContactName</v2:name>\r\n </v2:recipientContact>\r\n <v2:recipientAddress>\r\n <addressLine1>$recipientAddressLine1</addressLine1>\r\n <postTown>$postTown</postTown>\r\n <postcode>$postcode</postcode>\r\n <country>\r\n <countryCode>\r\n <code>$countryCode</code>\r\n </countryCode>\r\n </country>\r\n </v2:recipientAddress>\r\n <v2:items>\r\n <v2:item>\r\n <v2:numberOfItems>$noOfItems</v2:numberOfItems>\r\n <v2:weight>\r\n <unitOfMeasure>\r\n <unitOfMeasureCode>\r\n <code>$unitOfMeasure</code>\r\n </unitOfMeasureCode>\r\n </unitOfMeasure>\r\n <value>$weightValue</value>\r\n </v2:weight>\r\n </v2:item>\r\n </v2:items>\r\n <v2:senderReference>$sendersReference</v2:senderReference>\r\n </v2:requestedShipment>\r\n </v2:createShipmentRequest>\r\n </soapenv:Body>\r\n</soapenv:Envelope>", CURLOPT_HTTPHEADER => array( "accept: application/soap+xml", "accept-encoding: gzip,deflate", "connection: keep-alive", "content-type: text/xml", "host: api.royalmail.net", "soapaction: \"createShipment\"", "x-ibm-client-id: $clientId", "x-ibm-client-secret: $clientSecret" ),));

$response = curl_exec($curl);$err = curl_error($curl);

Page 10 of 19

curl_close($curl);

if ($err) { echo "cURL Error #:" . $err;} else { echo $response;}

?>

5.1.2Code VariablesCustomers must ensure that the required parameters (highlighted in yellow) in section 5.1.1 have the correct values populated when sending the request. These variables are fully documented in the Technical User Guide available on the Shipping API V2 page of the Royal Mail API (Developer) Portal.

Page 11 of 19

5.2 PHP HTTP (PHP with SOAP Client)PHP has an inbuilt SOAP client which can be used to instantiate the functionality needed to send SOAP request over a HTTP based connection. The PHP SOAP client has a class library which is used in the code below for creating, sending and receiving the SOAP message.The sample code provided in this section is compatible with PHP versions 5 through to 7.

5.2.1Sample Code (Request)<?php/*-------------------------------------------------------------------------------------------------------------------*//* This code has been written as a sample to demonstrate how the API call can be *//* made using the PHP SOAP client. The code also shows the auto generation of *//* password digest, encoded nonce and time when these values are created *//* can be calculated, to populate the WS-security header of the SAPI SOAP service. *//* The security header for the SAPI service needs to provide, *//* Username as - <wsse:Username>YOURUSENAME</wsse:Username> *//* where YOURUSENAME is the username provided by RMG *//* Password as - <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">PASSWORDDIGEST</wsse:Password> *//* where PASSWORDDIGEST is calculated as shown in the code below *//* Nonce as - <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">ENCODEDNONCE</wsse:Nonce> *//* where ENCODEDNONCE is shown in the code below *//* Creation date - <wsu:Created>CREATIONDATE</wsu:Created> *//* where CREATIONDATE is shown in the code below *//* *//* To make a successful API call by using the code below, one must: *//* a) Provide the right username *//* a) Change the password to your password *//*-------------------------------------------------------------------------------------------------------------------*/

$apiURL = "https://api.royalmail.net/shipping/v2";$dateTime = date('Y-m-d\TH:i:s');$applicationId = "xxx";$transactionId = "xx";$shippingDate = gmdate('Y-m-d');$shipmentType = "Delivery";$serviceOccurrence = "1";$serviceType = "1";$serviceCode = "xx";$serviceFormat = "x";$recipientName = "Tom";$recipientComplementaryName = ""; $recipientAddressLine1 = "3 Bowerman Close";$recipientAddressLine2 = "";$postTown = "London";$postcode = "EC1 4GW";$countryCode = "GB";$noOfItems = "x";$unitOfMeasure = "xx";$weightValue = "xxx";$sendersReference = "123ABC";

/* Change the values below to the ClientID and Secret values associated with the application you * registered on the API Developer Portal */$clientId = "xxx";

Page 12 of 19

$clientSecret = "xxx";

/* The values below should be changed to your actual username and password. If you store the password * as hashed in your database, you will need to change the code below to remove hashing */$username = "xxx";$password = “xxx”;

/* CREATIONDATE - The timestamp. The computer must be on correct time or the server you are * connecting may reject the password digest for security. */$creationDate = gmdate('Y-m-d\TH:i:s\Z');

/* NONCE - A random word. * The use of rand() may repeat the word if the server is very loaded. */$nonce = mt_rand();

/* PASSWORDDIGEST This is the way to create the password digest. As per OASIS standard * digest = base64_encode(Sha1(nonce + creationdate + Sha1(password))) * Note that we use a Sha1(password) instead of the plain password above */$nonce_date_pwd = $nonce.$creationDate.base64_encode(sha1($password, TRUE));$passwordDigest = base64_encode(sha1($nonce_date_pwd, TRUE));

/* ENCODEDNONCE - Now encode the nonce for security header */$encodedNonce = base64_encode($nonce);

/* Print all WS-Security values for debugging echo 'nonce: ' . $nonce . PHP_EOL;echo 'password digest: ' . $passwordDigest . PHP_EOL;echo 'encoded nonce: ' . $encodedNonce . PHP_EOL;echo 'creation date: ' . $creationDate . PHP_EOL;*/

$options = array( 'uri'=>'http://schemas.xmlsoap.org/soap/envelope/', 'style'=>SOAP_RPC, 'use'=>SOAP_ENCODED, 'soap_version'=>SOAP_1_1, 'connection_timeout'=>15, 'trace'=>true, 'encoding'=>'UTF-8', 'exceptions'=>true,

'location' => $apiURL,'stream_context' => stream_context_create(

['http' =>

['header'=> implode(

"\r\n",[

'Accept: application/soap+xml','X-IBM-Client-Id: ' . $clientId,'X-IBM-Client-Secret: ' . $clientSecret,

]),

],]

));

Page 13 of 19

$client = new SoapClient("https://api.royalmail.net/shipping/v2?wsdl", $options); $HeaderObjectXML = '<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>'.$username.'</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$passwordDigest.'</wsse:Password> <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.$encodedNonce.'</wsse:Nonce> <wsu:Created>'.$creationDate.'</wsu:Created> </wsse:UsernameToken> </wsse:Security>'; //Then create a new soap Var for this and push the header into soap$HeaderObject = new SoapVar( $HeaderObjectXML, XSD_ANYXML ); //Then finally push the header inot the SOAP header element$header = new SoapHeader( 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd', 'Security', $HeaderObject );$client->__setSoapHeaders($header); // Build the API request message $request = Array( 'integrationHeader' => array( 'dateTime' => $dateTime, 'version' => '2', 'identification' => array( 'applicationId' => $applicationId, 'transactionId' => $transactionId ), ), 'requestedShipment' => array( 'shipmentType' => array( 'code' => $shipmentType ), 'serviceOccurrence' => $serviceOccurrence, 'serviceType' => array( 'code' => $serviceType ), 'serviceOffering' => array( 'serviceOfferingCode' => array( 'code' => $serviceCode ) ), 'serviceFormat' => array( 'serviceFormatCode' => array( 'code' => $serviceFormat ) ), 'shippingDate' => $shippingDate, 'recipientContact' => array( 'name' => $recipientName, 'complementaryName' => $recipientComplementaryName ), 'recipientAddress' => array( 'addressLine1' => $recipientAddressLine1, 'addressLine2' => $recipientAddressLine2, 'postTown' => $postTown, 'postcode' => $postcode,

'country' => array(

Page 14 of 19

'countryCode' => array('code' => $countryCode)

) ), 'items' => array( 'item' => array( 'numberOfItems' => $noOfItems, 'weight' => array( 'unitOfMeasure' => array( 'unitOfMeasureCode' => array( 'code' => $unitOfMeasure ) ), 'value' => $weightValue ) ) ),

'senderReference' => $sendersReference ));

// Make the Shipping API calltry{ $response = $client->__soapCall('createShipment', array($request), array('soapaction' => 'https://api.royalmail.com/shipping/v2') );

// Echo/print the result obtained from the above SOAP call echo "<pre>".print_r($response, true)."</pre>"; }catch (Exception $e){ // Catch the error message and echo the last request for debug echo $e->getMessage(); echo " REQUEST:\n" . $client->__getLastRequest() . "\n"; die;}?>

5.2.2Code VariablesCustomers must ensure that the required parameters (highlighted in yellow) in section 5.2.1 have the correct values populated when sending the request. These variables are fully documented in the Technical User Guide available on the Shipping API V2 page of the Royal Mail API (Developer) Portal.

5.2.3ResponseThis section shows the response received as a result of making the API call using the sample code provided in section 5.2.1 after having provided valid values for the parameters highlighted in yellow.stdClass Object( [integrationHeader] => stdClass Object ( [dateTime] => 2016-06-27T11:05:32 [version] => 2

Page 15 of 19

[identification] => stdClass Object ( [applicationId] => RMG-API-X-01 [transactionId] => 15 ) ) [completedShipmentInfo] => stdClass Object ( [status] => stdClass Object ( [status] => stdClass Object ( [statusCode] => stdClass Object ( [code] => Allocated ) ) [validFrom] => 2016-06-27T17:05:33.000+02:00 ) [allCompletedShipments] => stdClass Object ( [completedShipments] => stdClass Object ( [weight] => stdClass Object ( [unitOfMeasure] => stdClass Object ( [unitOfMeasureCode] => stdClass Object ( [code] => g ) ) [value] => 1 ) [shipments] => stdClass Object ( [shipmentNumber] => TTT002837658GB [shipment] => stdClass Object ( [shipmentNumber] => TTT002837658GB [itemID] => 1002369 [status] => stdClass Object ( [status] => stdClass Object ( [statusCode] => stdClass Object ( [code] => Allocated ) ) [validFrom] => 2016-06-27T17:05:33.000+02:00 ) ) ) ) ) [requestedShipment] => stdClass Object

Page 16 of 19

( [shipmentType] => stdClass Object ( [code] => Delivery ) [serviceOccurrence] => 1 [serviceType] => stdClass Object ( [code] => 1 ) [serviceOffering] => stdClass Object ( [serviceOfferingCode] => stdClass Object ( [code] => CRL ) ) [serviceFormat] => stdClass Object ( [serviceFormatCode] => stdClass Object ( [code] => F ) ) [serviceEnhancements] => stdClass Object ( [enhancementType] => stdClass Object ( [serviceEnhancementCode] => stdClass Object ( ) ) ) [shippingDate] => 2016-06-27 [recipientContact] => stdClass Object ( [name] => Jon Doe [complementaryName] => SS [telephoneNumber] => stdClass Object ( ) ) [recipientAddress] => stdClass Object ( [addressLine1] => 23, Some Road [addressLine2] => [postTown] => London [postcode] => E1 ) [items] => stdClass Object ( [item] => stdClass Object ( [numberOfItems] => 1 [weight] => stdClass Object ( [unitOfMeasure] => stdClass Object

Page 17 of 19

( [unitOfMeasureCode] => stdClass Object ( [code] => g ) ) [value] => 1 ) ) ) ) ))

5.3 Testing Framework The sample code provided in sections 5.1.1 and 5.2.1 has been tested on a number of online PHP frameworks as outlined below: http://sandbox.onlinephpfunctions.com

This online framework was used to test the WS-Security sample code only in order to verify the automatic generation of the password digest. The nonce and password digest generated from this test framework was then used in a SOAP UI project to test the API operation. It was verified that the operation returned the HTTP 200 OK when the auto generated nonce and password digest was used.Please note that it was not possible to test the entire PHP sample code on this online tool. On this basis, only the sample code for the WS-Security was tested.

http://phpfiddle.org This online framework was used to send the API request using the sample code provided in sections 5.1.1 and 5.2.1. A real username together with the nonce and password digest generated from the sample code were used to test the API operation. The code in sections 5.1.1 and 5.2.1 was populated with actual business data and the createShipment operation was verified after it returned a HTTP 200 OK with the expected response.Follow the steps below to test the code using this online tool:

o Copy the entire code (see sections 5.1.1 / 5.2.1) to the CodeSpace tab of this online tool (see screenshot below).

o Provide the relevant values for all required variables (e.g. username, applicationId, transactionId, serviceType, serviceCode etc).

o Hit ‘Run-F9’ and see the output/response on the Window tab.

Page 18 of 19

Royal Mail, the cruciform, the colour red and all ® are registered trademarks and all ™ are trademarks of Royal Mail Group Ltd. Shipping API V2 Sample Code User Guide July 2016 © Royal Mail Group Ltd 2016.

All rights reserved.

Page 19 of 19