PeopleVox

Carrier Integration Platform Guide - BETA


Carrier Integration Platform Guide - BETA v0.2



Table of Contents

  1. Introduction to Carrier Integrations

    1.1 What does a carrier integration do?

    1.2 How do I build a carrier integration?

  2. Frequently Asked Questions

  3. Change log

1. Introduction to Carrier Integrations

1.1 What does a carrier integration do?

A carrier integration with Peoplevox allows Peoplevox users to print carrier labels for their orders as they despatch them, and for Peoplevox to obtain the tracking numbers back from the carrier.

Your carrier integration will be responsible for accepting shipment data from Peoplevox, communicating with carrier APIs to generate labels, and then communicating the results back to Peoplevox.

Your response back to Peoplevox contains URLs to the requested documents (as PDF files), and one or more tracking numbers for the shipment.

Peoplevox will then pull down the documents from those URLs, and send them to the warehouse printers. Peoplevox will also save the tracking data, and fire off the relevant tracking number events to any subscribers.

1.2 How do I build a carrier integration?

1.2.1 Architecture

To build a carrier integration, you will need to create and host a simple API that Peoplevox can connect to. This API will listen for, and respond to, shipment notifications from Peoplevox. If you already have an existing API, then you will need to create and host a facade that meets the specifications below, and Peoplevox will use that facade as the endpoint.

You will then need to register your API with the Peoplevox account that will be using the integration, so that the WMS knows where to send shipment data.

When an operator in Peoplevox requests carrier documentation (which typically occurs as the final step of the Peoplevox despatch process), the platform will POST you a JSON payload that contains:

Your endpoint accepts that POST, holds the connection open while it talks to your back-end to generate the requested documents, and then responds with tracking numbers and URLs to your documents.

That API is the touch-point between Peoplevox and your system. So long as you accept the shipment data, and return a response in the formats described in this document, then you are free to implement the logic between that request and response as you see fit.

This document describes your endpoint as a RESTful API because the communication process can be framed in the context of resource creation. The POST from the Peoplevox platform is a request for your endpoint to generate a Document Bundle resource (a full description of this is included later in the document).

The Document Bundle resource is essentially a log of the request and response. Your endpoint:

Your endpoint is only required to respond to POST requests, but it may optionally respond to GET requests as well. It must NOT permit updates to existing Document Bundles, regardless of the verb used. Framing the process like this ensures that effective and reliable logging is baked into every integration.

1.2.2 Building your endpoint

Your endpoint needs to accept a POST request from the Peoplevox platform, which will contain a JSON payload that describes a shipment and the documentation requested for it.

This will always be an HTTPS POST request, and will include an Authorization header that provides an API key in the form of a Bearer token.

The request will provide Accept and Content-Type headers of application/json.

Due to the fact that the endpoint is a layer of abstraction between Peoplevox and the carrier platform itself, you have some flexibility in the way you transform requests from Peoplevox into the requests that you make to the carrier platform.

A common example of this principle is authentication. This document defines that the authentication process between Peoplevox and the endpoint uses an API key as a Bearer token, but that does not necessarily require the same authentication process to be implemented between the endpoint and your back-end services. For example, your endpoint might authenticate the request from Peoplevox using the Bearer token, and then provide a different authentication token to your carrier system.

Your integration is responsible for specifying the types of documentation that it supports, as well as the different types of tracking number. You specify these when you register your endpoint.

A typical integration would support between one and three of the following types of document:

And one or both of these types of tracking number:

However, you are not constrained by these. Your integration defines the types of document it supports, and that determines what the Peoplevox user is able to request from your integration. Please refer to the section on “Registering your endpoint” for more information.

1.2.2.1 The DocumentBundle resource

The DocumentBundle resource represents the combination of a request and a response. It acts as a log of the data provided by Peoplevox, and the data returned by the endpoint. The basic structure is just a combination of these two entities:


{
	"request" : 	{	},
	"response" : 	{	}
}

For example, the DocumentBundle for a successful call with some test data would look something like this (the details of the request and response are described below):


{
	"request" : {
		"metadata" : {
			"schemaVersion" : "1.0",
			"platformVersion" : "1.0",
			"documentBundleEndpointVersion" : "1.0"
		},
		"despatchPackage" : {
			"despatchPackageId" : 1,
			"despatch" : {
				"despatchNumber" : "DES100",
				"carrier" : {
					"name" : "Royal Mail",
					"reference" : "RM"
				},
				"serviceType" : {
					"name" : "Royal Mail Next Day",
					"code" : "RM24",
					"outboundReference" : ""
				},
				"loadReference" : "",
				"salesOrder" : {
					"salesOrderNumber" : "SO100",
					"customer" : {
						"name" : "Matt Thomson",
						"reference" : "123456789",
						"firstName" : "Matt",
						"lastName" : "Thomson",
						"phone" : "",
						"mobile" : "",
						"email" : "matt.thomson@peoplevox.com",
						"creditLimit" : "",
						"paymentTerm" : ""
					},
					"customerPurchaseOrderReferenceNumber" : "",
					"shippingAddress" : {
						"line1" : "119",
						"line2" : "Marylebone Road",
						"townCity" : "London",
						"region" : "",
						"postCode" : "NW1 5PU",
						"countryName" : "United Kingdom",
						"countryCode" : "UK"
					},
					"invoiceAddress" : {
						"line1" : "119",
						"line2" : "Marylebone Road",
						"townCity" : "London",
						"region" : "",
						"postCode" : "NW1 5PU",
						"countryName" : "United Kingdom",
						"countryCode" : "UK"
					},
					"requestedDeliveryDate" : "01/01/2018 00:00:00",
					"shippingCost" : "0.00",
					"email" : "matt.thomson@peoplevox.com",
					"contactName" : "Matt Thomson",
					"paymentMethod" : "Cash",
					"totalSale" : "0.00",
					"discount" : "0.00",
					"taxPaid" : "0.00",
					"createdDate" : "",
					"channelName" : "My website",
					"attribute1" : "",
					"attribute2" : "",
					"attribute3" : "",
					"attribute4" : "",
					"attribute5" : "",
					"site" : "PrimarySite"
				}
			},
			"weight" : "0.00",
			"height" : "0.00",
			"width" : "0.00",
			"depth" : "0.00",
			"packageType" : {
				"name" : "",
				"barcode" : ""
			},
			"packageNumber" : 1,
			"carrier" : {
				"name" : "Royal Mail",
				"reference" : "RM"
			},
			"serviceType" : {
				"name" : "Royal Mail Next Day",
				"code" : "RM24",
				"outboundReference" : ""
			},
			"despatchItems" : [
			{
				"itemType" : {
					"itemCode" : "ItemA",
					"name" : "Item A",
					"barcode" : "ITEMA001",
					"description" : "This is a lovely widget",
					"itemGroup" : "Widgets",
					"unitOfMeasure" : {
						"name" : "Unit",
						"symbol" : "EA"
					},
					"defaultSupplierPartNumber" : "MYWIDGETA",
					"buyPrice" : "0.00",
					"wholesalePrice" : "0.00",
					"retailPrice" : "0.00",
					"weight" : "1.00",
					"weightMeasure" : "kg",
					"height" : "1.00",
					"width" : "1.00",
					"depth" : "1.00",
					"dimensionMeasure" : "cm",
					"tags" : "",
					"taxCode" : "",
					"attribute1" : "",
					"attribute2" : "",
					"attribute3" : "",
					"attribute4" : "",
					"attribute5" : "",
					"attribute6" : "",
					"attribute7" : "",
					"attribute8" : "",
					"attribute9" : "",
					"attribute10" : "",
					"attribute11" : "",
					"attribute12" : "",
					"attribute13" : "",
					"attribute14" : "",
					"attribute15" : ""
				},
				"quantity" : 1,
				"container" : {
					"barcode" : "",
					"reference" : ""
				}
			}
			]
		},
		"oldPrintRequests" : [
			{
				"printRequestId" : 1,
				"documentReference" : "Carrier label"
			},
			{
				"printRequestId" : 2,
				"documentReference" : "Customs documentation"
			},
			{
				"printRequestId" : 3,
				"documentReference" : "Returns label"
			}
		]
	},
	"response" : {
		"status" : "success",
		"message" : null,
		"data" : {
			"trackingNumbers" :  [
				{
					"trackingType" : "outbound",
					"trackingNumber": "TRCK123456789"
				},
				{
					"trackingType" : "returns",
					"trackingNumber": "TRCK987654321"
				}
			],
			"newPrintRequests" : [
				{
					"printRequestId" : 1,
					"printTemplateUrl" : "https://mycarrierintegrationhost.com/labels/1_label.pdf",
					"status" : "success"
				},
				{
					"printRequestId" : 2,
					"printTemplateUrl" : "https://mycarrierintegrationhost.com/customs/1_customs.pdf",
					"status" : "success"
				},
				{
					"printRequestId" : 3,
					"printTemplateUrl" : "https://mycarrierintegrationhost.com/returnslabels/1_returns.pdf",
					"status" : "success"
				}
			]
		}
	}
}

1.2.2.2 Request

The Request entity describes three key pieces of data:

The metadata specifies version numbers for various properties of the integration.

The despatchPackage contains the details of the package to be shipped. It includes the carrier and service level, the destination address, dimensions, and details of the products inside it. It also contains a reference to the original sales order.

The oldPrintRequests contains the collection of documents that the user in Peoplevox has requested from your integration. Each of these contains a reference that links back to the documentation types that you indicated your integration can support. For example, if you indicate that you support a document type called “foo”, then this collection can contain documentReferences of “foo”.


{
	"metadata" : {
		"schemaVersion" : "1.0",
		"platformVersion" : "1.0",
		"documentBundleEndpointVersion" : "1.0"
	},
	"despatchPackage" : {
		"despatchPackageId" : 1,
		"despatch" : {
			"despatchNumber" : "DES100",
			"carrier" : {
				"name" : "Royal Mail",
				"reference" : "RM"
			},
			"serviceType" : {
				"name" : "Royal Mail Next Day",
				"code" : "RM24",
				"outboundReference" : ""
			},
			"loadReference" : "",
			"salesOrder" : {
				"salesOrderNumber" : "SO100",
				"customer" : {
					"name" : "Matt Thomson",
					"reference" : "123456789",
					"firstName" : "Matt",
					"lastName" : "Thomson",
					"phone" : "",
					"mobile" : "",
					"email" : "matt.thomson@peoplevox.com",
					"creditLimit" : "",
					"paymentTerm" : ""
				},
				"customerPurchaseOrderReferenceNumber" : "",
				"shippingAddress" : {
					"line1" : "119",
					"line2" : "Marylebone Road",
					"townCity" : "London",
					"region" : "",
					"postCode" : "NW1 5PU",
					"countryName" : "United Kingdom",
					"countryCode" : "UK"
				},
				"invoiceAddress" : {
					"line1" : "119",
					"line2" : "Marylebone Road",
					"townCity" : "London",
					"region" : "",
					"postCode" : "NW1 5PU",
					"countryName" : "United Kingdom",
					"countryCode" : "UK"
				},
				"requestedDeliveryDate" : "01/01/2018 00:00:00",
				"shippingCost" : "0.00",
				"email" : "matt.thomson@peoplevox.com",
				"contactName" : "Matt Thomson",
				"paymentMethod" : "Cash",
				"totalSale" : "0.00",
				"discount" : "0.00",
				"taxPaid" : "0.00",
				"createdDate" : "",
				"channelName" : "My website",
				"attribute1" : "",
				"attribute2" : "",
				"attribute3" : "",
				"attribute4" : "",
				"attribute5" : "",
				"site" : "PrimarySite"
			}
		},
		"weight" : "0.00",
		"height" : "0.00",
		"width" : "0.00",
		"depth" : "0.00",
		"packageType" : {
			"name" : "",
			"barcode" : ""
		},
		"packageNumber" : 1,
		"carrier" : {
			"name" : "Royal Mail",
			"reference" : "RM"
		},
		"serviceType" : {
			"name" : "Royal Mail Next Day",
			"code" : "RM24",
			"outboundReference" : ""
		},
		"despatchItems" : [
		{
			"itemType" : {
				"itemCode" : "ItemA",
				"name" : "Item A",
				"barcode" : "ITEMA001",
				"description" : "This is a lovely widget",
				"itemGroup" : "Widgets",
				"unitOfMeasure" : {
					"name" : "Unit",
					"symbol" : "EA"
				},
				"defaultSupplierPartNumber" : "MYWIDGETA",
				"buyPrice" : "0.00",
				"wholesalePrice" : "0.00",
				"retailPrice" : "0.00",
				"weight" : "1.00",
				"weightMeasure" : "kg",
				"height" : "1.00",
				"width" : "1.00",
				"depth" : "1.00",
				"dimensionMeasure" : "cm",
				"tags" : "",
				"taxCode" : "",
				"attribute1" : "",
				"attribute2" : "",
				"attribute3" : "",
				"attribute4" : "",
				"attribute5" : "",
				"attribute6" : "",
				"attribute7" : "",
				"attribute8" : "",
				"attribute9" : "",
				"attribute10" : "",
				"attribute11" : "",
				"attribute12" : "",
				"attribute13" : "",
				"attribute14" : "",
				"attribute15" : ""
			},
			"quantity" : 1,
			"container" : {
				"barcode" : "",
				"reference" : ""
			}
		}
		]
	},
	"oldPrintRequests" : [
		{
			"printRequestId" : 1,
			"documentReference" : "Carrier label"
		},
		{
			"printRequestId" : 2,
			"documentReference" : "Customs documentation"
		},
		{
			"printRequestId" : 3,
			"documentReference" : "Returns label"
		}
	]
}

1.2.2.3 Response - Success

If you are able to successfully parse the data from Peoplevox, contact the carrier system, and obtain labels and tracking numbers, then your endpoint should respond with a success message in the following format.

In this example, the endpoint responded with two types of tracking number, and three different documents:


{
	"status" : "success",
	"message" : null,
	"data" : {
		"trackingNumbers" :  [
			{
				"trackingType" : "outbound",
				"trackingNumber": "TRCK123456789"
			},
			{
				"trackingType" : "returns",
				"trackingNumber": "TRCK987654321"
			}
		],
		"newPrintRequests" : [
			{
				"printRequestId" : 1,
				"printTemplateUrl" : "https://mycarrierintegrationhost.com/labels/1_label.pdf",
				"status" : "success"
			},
			{
				"printRequestId" : 2,
				"printTemplateUrl" : "https://mycarrierintegrationhost.com/customs/1_customs.pdf",
				"status" : "success"
			},
			{
				"printRequestId" : 3,
				"printTemplateUrl" : "https://mycarrierintegrationhost.com/returnslabels/1_returns.pdf",
				"status" : "success"
			}
		]
	}
}

The success message indicates that the Peoplevox platform should attempt to print the indicated labels and assign the tracking numbers.

The Peoplevox platform will extract each of the tracking numbers provided and format them according to a template defined by the user in Peoplevox; for example a user may wish to concatenate the “outbound” and “returns” tracking numbers into a single string.

In some cases, users in Peoplevox may request a document that is not required. A common example of this is where a user requests customs documentation for a domestic shipment. In these situations, the overall response should still be treated as a success, but you should use the “not required” status on the documents that are not needed.

This status lets Peoplevox know that there was no error during the request, but fewer documents will be printed than were requested:


{
	"status" : "success",
	"message" : null,
	"data" : {
		"trackingNumbers" :  [
			{
				"trackingType" : "outbound",
				"trackingNumber": "TRCK123456789"
			},
			{
				"trackingType" : "returns",
				"trackingNumber": "TRCK987654321"
			}
		],
		"newPrintRequests" : [
			{
				"printRequestId" : 1,
				"printTemplateUrl" : "https://mycarrierintegrationhost.com/labels/1_label.pdf",
				"status" : "success"
			},
			{
				"printRequestId" : 2,
				"printTemplateUrl" : null,
				"status" : "not required"
			},
			{
				"printRequestId" : 3,
				"printTemplateUrl" : "https://mycarrierintegrationhost.com/returnslabels/1_returns.pdf",
				"status" : "success"
			}
		]
	}
}

1.2.2.4 Response - Partial Success

There are situations in which parts of the request may succeed while other parts fail. For example, a carrier may successfully generate one of the two requested documents, but fail to generate the other. In that case, a “partial” response is appropriate.

The structure of this response is the same as a full success, but your endpoint should return some indication of which aspects failed and why.


{
	"status" : "partial",
	"message" : "Unable to generate customs documentation: insufficient product data",
	"data" : {
		"trackingNumbers" :  [
			{
				"trackingType" : "outbound",
				"trackingNumber": "TRCK123456789"
			},
			{
				"trackingType" : "returns",
				"trackingNumber": "TRCK987654321"
			}
		],
		"newPrintRequests" : [
			{
				"printRequestId" : 1,
				"printTemplateUrl" : "https://mycarrierintegrationhost.com/labels/1_label.pdf",
				"status" : "success"
			},
			{
				"printRequestId" : 2,
				"printTemplateUrl" : null,
				"status" : "fail"
			},
			{
				"printRequestId" : 3,
				"printTemplateUrl" : "https://mycarrierintegrationhost.com/returnslabels/1_returns.pdf",
				"status" : "success"
			}
		]
	}
}

1.2.2.5 Response - Failure

There are situations in which a request may completely fail. For example, the user may have requested documentation for a carrier that does not support the requested country. In these situations, a “fail” response is appropriate.

As with the partial success, the structure of the response is the same:


{
	"status" : "fail",
	"message" : "The requested carrier does not support shipments from the UK",
	"data" : {
		"trackingNumbers" :  null,
		"newPrintRequests" : [
			{
				"printRequestId" : 1,
				"printTemplateUrl" : null,
				"status" : "fail"
			},
			{
				"printRequestId" : 2,
				"printTemplateUrl" : null,
				"status" : "fail"
			},
			{
				"printRequestId" : 3,
				"printTemplateUrl" : null,
				"status" : "fail"
			}
		]
	}
}

1.2.3 Registering your endpoint

This part of the platform is still under construction. In the future, you will be able to submit an API request to Peoplevox to register your endpoint and provide the relevant credentials that Peoplevox will then need to submit shipment data.

In the interim, please contact Peoplevox directly if you wish to build an integration on this platform.

1.2.4 Linking your endpoint to documents in Peoplevox

Once you have registered your endpoint, a user in Peoplevox will then need to link your connection to print templates within Peoplevox.

The print templates are what the pack bench operator will interact with during the despatch process. When performing a despatch, they will request that Peoplevox prints one or more templates. If one of those templates is linked to your connection, then Peoplevox will trigger a call out to your endpoint.

If your endpoint responds with a URL to a new document, then Peoplevox will replace the template that the user queued with your document.

If your endpoint responds with an error or is unable to respond within the timeout, then the Peoplevox platform will simply print the document that the user queued (these Peoplevox templates are known as “failovers”).

Peoplevox Clients are encouraged to design these failover templates to be visually distinct from the labels that pack bench operators would typically receive from carriers. This ensures that the operator is immediately aware that a problem has occurred with that package, and they can set it aside and move on to the next.

For this reason, Clients are also encouraged to make sure that the failover templates contain enough information to be able to easily identify the package later.

A good example of a failover template would have a large-print warning message at the top, and include a barcode that represents the sales order number, as well as potentially address information and a list of the items in the package. That ensures that the order can easily be identified later, and the user can confirm that the package still contains the expected items.

2. Frequently Asked Questions

How do I send a label to Peoplevox for printing?

You would return a URL to your PDF file on the response when Peoplevox sends a request to your API.

Do I need to download the labels and host them myself?

Not necessarily, but you must provide Peoplevox with a URL from which the document can be obtained
and printed. Some carriers will host the labels themselves and provide a URL, and others with 
save the label from the carrier to a cloud storage platform, then return the URL to that.

What should I do if my endpoint receives a document request with some bad data from Peoplevox, like an invalid address?

In this case, you should respond to the request with a "fail" status so that Peoplevox can print the 
failover label. 
You should also provide the Peoplevox user with an easy process for correcting the shipment data and 
re-printing the label.
Some data can be corrected within Peoplevox and the document request resubmitted, but other data is 
locked at the point of shipment.

What should I do if I receive multiple requests for the same shipment (i.e. for the same Peoplevox package)?

If the first request for a package succeeded, and the documentation has not been voided in the carrier 
system, then you should respond with the same documentation and tracking numbers.
If the documentation has been voided, or the previous documentation request failed, then you should 
provide a new set of documentation and tracking numbers.
You should try to optimise the shipping with the carrier. Typically, that means collecting both 
packages into the same consignment.

Is it possible for my carrier system to send the labels directly to the printer?

This is not currently supported, but may be added to the platform at a later date.

3. Change Log

v0.2

* Corrected a minor issue with the expected format of the JSON response payload; "trackingNumbers" and 
"newPrintRequests" are expected to be nested within a "data" property on the response.

Document created

* First (beta) release of the carrier integration platform documentation