Creating and updating Shipments
This guide will walk you through creating and updating Shipments using the Montonio API. More information can be found in the API reference.
Creating a Shipment
The Shipment object is the core entity in this API. Ideally, this object should match the Order in your system if this API is connected to an e-commerce platform. This means one Order equals one Shipment. You need the Shipment object to create a label file.
This is a complete example of how to create a Shipment. Before continuing, ensure you have the type and ID of the shipping method you would like to use. The process is as follows:
- Gather the sender data you will use for the Shipment. The sender is not mandatory and can be left out. If left out, we will default to your store’s sender details, which can be updated in our Partner System.
- Gather the receiver data you will use for the Shipment.
- Get the type and ID of the shipping method. The API currently supports couriers and pickup points.
- Gather the parcel data. You can pass one or more parcels as an array. Currently, we only require you to specify the parcel’s weight, but you can also specify the length, width, and height, which will be validated against the rules specified by the carriers.
- Optionally, include product information. Adding products enables the pick list feature for warehouse fulfillment and displays the ordered products on the tracking page.
- If you also use our Payments solution, specify the Montonio Order ID using the
montonioOrderUuidproperty. We will use this to link the Shipment to the Order. - To create, make a POST request to
/shipments.
import axios from 'axios';
const data = JSON.stringify({ sender: { name: 'Jimmy Sender', companyName: 'Company Y', streetAddress: 'Kai 1', locality: 'Tallinn', region: 'Harjumaa', postalCode: '10111', country: 'EE', phoneCountryCode: '372', phoneNumber: '53334770', email: 'support@montonio.com', }, receiver: { name: "Johnny Receiver", companyName: 'Company X', streetAddress: 'Kai 11', locality: 'Tallinn', region: 'Harjumaa', postalCode: '10111', country: 'EE', phoneCountryCode: '372', phoneNumber: '53334770', email: 'support@montonio.com', }, montonioOrderUuid: '240b8d02-1b59-4685-87e6-c37ff4a2bacc', merchantReference: 'test 1', shippingMethod: { type: 'pickupPoint', id: '377c3b06-0967-4ff2-b28a-372cab234898', }, parcels: [ { weight: 1, }, ], products: [ { sku: 'PROD-001', name: 'Wireless Headphones', quantity: 1, price: 79.99, currency: 'EUR', }, { sku: 'PROD-002', name: 'Phone Case', quantity: 2, price: 15.00, currency: 'EUR', }, ],});
const config = { method: 'post', url: 'https://shipping.montonio.com/api/v2/shipments', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: 'Bearer [your_token]', }, data: data,};
async function makeRequest() { try { const response = await axios.request(config); console.log(JSON.stringify(response.data)); } catch (error) { console.log(error); }}
makeRequest();The API response will have the following structure:
{ "id": "1f83f4c1-cccc-4dd5-8eae-837e6a88362f", "createdAt": "2024-06-13T08:50:45.376Z", "status": "pending", "montonioOrderUuid": "240b8d02-1b59-4685-87e6-c37ff4a2bacc", "merchantReference": "test 1", "carrierShipmentId": null, "shippingMethod": { "type": "pickupPoint", "id": "377c3b06-0967-4ff2-b28a-372cab234898", "carrierCode": "omniva", "countryCode": "EE" }, "sender": { "id": "280d65e9-e9bc-4e41-ac18-1504f1572400", "name": "Sender Y", "companyName": "Company Y", "streetAddress": "Kai 1", "locality": "Tallinn", "region": "Harjumaa", "postalCode": "10111", "country": "EE", "phoneCountryCode": "372", "phoneNumber": "53334770", "email": "support@montonio.com" }, "receiver": { "id": "a8c43180-56a8-42c4-bec9-7c50af7e0684", "firstName": null, "lastName": null, "name": "Receiver X", "companyName": "Company X", "streetAddress": "Kai 11", "locality": "Tallinn", "region": "Harjumaa", "postalCode": "10111", "country": "EE", "phoneCountryCode": "372", "phoneNumber": "53334770", "email": "support@montonio.com" }, "parcels": [ { "id": "ba5184ea-6470-4a2d-b216-2eebc75db40e", "weight": 1, "length": null, "height": null, "width": null, "carrierParcelId": null, "trackingLink": null } ], "store": { "id": "088ae409-ae24-4a3c-a640-5c269f732caa" }, "products": [ { "id": "f1a2b3c4-d5e6-7890-abcd-ef1234567890", "createdAt": "2024-06-13T08:50:45.376Z", "sku": "PROD-001", "name": "Wireless Headphones", "barcode": null, "quantity": 1, "price": 79.99, "currency": "EUR", "attributes": null, "imageUrl": null }, { "id": "a1b2c3d4-e5f6-7890-abcd-ef0987654321", "createdAt": "2024-06-13T08:50:45.376Z", "sku": "PROD-002", "name": "Phone Case", "barcode": null, "quantity": 2, "price": 15.00, "currency": "EUR", "attributes": null, "imageUrl": null } ]}Synchronous vs Asynchronous Flow
By default, shipments are processed asynchronously. When you create a shipment, it returns immediately with status pending, and the actual registration with the carrier happens in the background. You receive a webhook notification when the status changes to registered or registrationFailed.
For simpler integrations, you can opt for synchronous processing by setting synchronous: true in your request. This makes the API wait for carrier registration to complete before returning, so you get the final status directly in the response.
Synchronous example
import axios from 'axios';
const data = JSON.stringify({ receiver: { name: "Johnny Receiver", companyName: 'Company X', streetAddress: 'Kai 11', locality: 'Tallinn', region: 'Harjumaa', postalCode: '10111', country: 'EE', phoneCountryCode: '372', phoneNumber: '53334770', email: 'support@montonio.com', }, merchantReference: 'test 1', shippingMethod: { type: 'pickupPoint', id: '377c3b06-0967-4ff2-b28a-372cab234898', }, parcels: [ { weight: 1, }, ], synchronous: true, // Enable synchronous processing});
const config = { method: 'post', url: 'https://shipping.montonio.com/api/v2/shipments', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: 'Bearer [your_token]', }, data: data,};
async function makeRequest() { try { const response = await axios.request(config); // Response will have status "registered" or "registrationFailed" directly console.log(JSON.stringify(response.data)); } catch (error) { console.log(error); }}
makeRequest();With synchronous processing, the response will include the final registration status:
{ "id": "1f83f4c1-cccc-4dd5-8eae-837e6a88362f", "createdAt": "2024-06-13T08:50:45.376Z", "status": "registered", "merchantReference": "test 1", "carrierShipmentId": "ABC123456", "shippingMethod": { "type": "pickupPoint", "id": "377c3b06-0967-4ff2-b28a-372cab234898", "carrierCode": "omniva", "countryCode": "EE" }, "parcels": [ { "id": "ba5184ea-6470-4a2d-b216-2eebc75db40e", "weight": 1, "carrierParcelId": "00364300487153076531", "trackingLink": "https://itella.ee/et/private-customer/parcel-tracking?trackingCode=00364300487153076531" } ]}Adding Products to Shipments
Including product information in your shipments enables two key features:
- Pick List Generation: Generate pick lists for warehouse fulfilment through the Partner System, enabling efficient gathering of items for shipments.
- Tracking Page Display: Show ordered products on the customer-facing tracking page, improving the delivery experience.
Product Fields
| Field | Required | Description |
|---|---|---|
sku | Yes | Product SKU identifier. Max 100 characters. |
name | Yes | Product name. Max 255 characters. |
quantity | Yes | Product quantity. Max 999. Decimals allowed. |
barcode | No | Product barcode (any format). Max 100 characters. |
price | No | Product unit price. Max 2 decimal places. |
currency | No | ISO 4217 currency code (e.g., EUR, USD). |
attributes | No | Custom key-value attributes (e.g., {"color": "Red", "size": "M"}). |
imageUrl | No | URL to product image. Displayed on tracking page. |
storeProductUrl | No | URL to product page in your store. |
description | No | Product description. Max 5000 characters. |
Updating a Shipment
It’s possible that the system fails to register the Shipment with the carrier if the carrier rejects the request with an error. In such cases, we set the shipment status to registrationFailed. A common issue causing this is an incorrect receiver phone number.
To resolve this problem, you can update the Shipment, and the system will automatically attempt to register the Shipment again.
Let’s assume that the receiver entered an incorrect phone number and that you want to update the Shipment. Example below:
import axios from 'axios';
const data = JSON.stringify({ "receiver": { "phoneCountryCode": "372", "phoneNumber": "53334770" }});
const config = { method: 'patch', url: 'https://shipping.montonio.com/api/v2/shipments/fea857c1-3f39-42b3-93b5-d7644c8b2a67', headers: { 'Content-Type': 'application/json', Authorization: 'Bearer [your_token]', }, data: data};
async function makeRequest() { try { const response = await axios.request(config); console.log(JSON.stringify(response.data)); } catch (error) { console.log(error); }}
makeRequest();The API response will have the following structure:
{ "id": "4ddaf28a-244f-4b05-b3dd-f63e0d133690", "createdAt": "2024-06-14T11:55:07.067Z", "status": "registered", "montonioOrderUuid": null, "merchantReference": "order 1", "sender": { "id": "cc10856d-9e7d-4f3b-988f-eee0c10e8df8", "name": "Sender Y", "companyName": "Company Y", "streetAddress": "Kai 1", "locality": "Tallinn", "region": "Harjumaa", "postalCode": "10111", "country": "EE", "phoneCountryCode": "372", "phoneNumber": "53334770", "email": "support@montonio.com" }, "receiver": { "id": "dbab1c4f-d762-422e-8561-aa55dc8fa0bf", "firstName": null, "lastName": null, "name": "Receiver X", "companyName": "Company X", "streetAddress": "Kai 11", "locality": "Tallinn", "region": "Harjumaa", "postalCode": "10111", "country": "EE", "phoneCountryCode": "372", "phoneNumber": "53334770", "email": "support@montonio.com" }, "parcels": [ { "id": "2449caea-f761-43f3-938f-0e507a68d1a4", "weight": 1, "length": null, "height": null, "width": null, "carrierParcelId": "00364300487153076531", "trackingLink": "https://itella.ee/et/private-customer/parcel-tracking?trackingCode=00364300487153076531" } ], "shippingMethod": { "id": "e61bef79-cfdc-462e-8d57-a77a0c54abba", "type": "pickupPoint", "carrierCode": "smartpost", "countryCode": "EE" }, "carrierShipmentId": null, "store": { "id": "5d165f67-184f-451a-b819-214aabe25c00" }, "products": null}Webhook notification
Continuing from the previous example, the following status from pending will be either registrationFailed or registered. Our system will automatically attempt to register the Shipment again if the status is registrationFailed.
We also track the delivery status of the Shipment. This means the status can change from registered to inTransit, awaitingCollection, delivered, or returned. In addition to getting delivery status updates, you can enable our tracking page for your customers in the Partner System.
We will send a webhook notification for all status updates, so refer to the guide on webhooks.
Some errors which might occur during the request are listed below:
| Code | Description |
|---|---|
400 | Bad request. Please double-check the request body. You will get a more detailed error message. |
401 | Unauthorized. Please check if the JWT was generated correctly and the accessKey and secretKey are correct. |
500 | Internal server error. Something went wrong on our side. |