Importing Shipments via File Upload
This tutorial guides you through the process of importing multiple shipments into the Visiwise platform at once by uploading a CSV, XLS, or XLSX file. This is the most efficient method for bulk operations.
The import process involves five main steps:
- Get your Visiwise API Key.
- Authenticate your API requests.
- Prepare Your File.
- Upload the File.
- Monitor the Import Status.
- Review the Results.
Step 1: Get Your Visiwise API Key
To begin, you need to get your Visiwise API Key from your account dashboard by following the instructions in the Authentication section.
Step 2: Authenticate Your API Requests
The Visiwise API uses token-based authentication. To authenticate your requests, you must include your API Key in the Authorization header as a Bearer token.
Here is an example of an authenticated request using cURL:
- cURL
curl -X GET "https://www.visiwise.co/api/v1/shipments/" \
-H "Authorization: Bearer YOUR_VISIWISE_API_KEY"
Step 3: Prepare Your File
Next, you need to create a CSV, XLS, or XLSX file containing your shipment data. The first row of your file must be a header row with column names that exactly match the ones specified below.
File Headers
| Header (Case-sensitive) | Required | Example | Description |
|---|---|---|---|
tracking_number | Yes | MSDU8525700 | The Bill of Lading, booking, or container number. |
tracking_type | Yes | container | The type of number provided. Must be one of container, bill_of_lading, or booking. |
reference | No | ref-C006 | Your unique identifier for this shipment. If this reference exists, the existing shipment will be updated. |
carrier | No | MSCU | The SCAC code for the shipping carrier (e.g., MSCU for MSC). If tracking_type is container, you can set this to "AUTO" to let Visiwise detect the carrier automatically. |
name | No | Shipment of Coconuts & Apples | A friendly name for the shipment. |
viewers | No | [email protected], [email protected] | A comma-separated list of email addresses for users you want to share this shipment with (view-only). |
tags | No | Priority, Perishable | A comma-separated list of tags to categorize the shipment. |
assignees | No | [email protected], [email protected] | A comma-separated list of email addresses for team members you want to assign to this shipment. |
cf_wdgpuzcr89 | No | PO-12345 | To set a custom field value, use the format cf_{customfieldslug}. The custom field must already exist. |
Example CSV File Content
Here is an example of a correctly formatted CSV file.
tracking_number,tracking_type,reference,carrier,name,viewers,tags,assignees,cf_wdgpuzcr89
MSDU8525700,container,ref-C006,MSCU,Coconuts & Apples,"[email protected], [email protected]","Goods, Import","[email protected], [email protected]",PO-111
MSNU5702988,container,ref-C007,MSCU,Electronics Shipment,"[email protected], [email protected]",Electronics,"[email protected], [email protected]",PO-222
Step 4: Upload the File
Now you can upload your file to the API. You send a POST request to the /v1/shipments/imports/file endpoint. The platform processes your file in the background (asynchronously).
The API will respond immediately with a ShipmentRequestBatch object, which includes a unique id. You will use this id in the next step to check the status of your import.
Each reference must be unique within your workspace. If a reference already exists, the shipment will be updated rather than created.
- Python
- cURL
import requests
import json
BASE_URL = "https://www.visiwise.co"
API_KEY = "YOUR_VISIWISE_API_KEY"
# Headers for application/json requests.
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
# The endpoint for file uploads
upload_url = f"{BASE_URL}/api/v1/shipments/imports/file"
# Headers for multipart/form-data requests.
# Note: The 'requests' library sets the 'Content-Type' with the correct boundary automatically.
upload_headers = {
"Authorization": f"Bearer {API_KEY}"
}
# Prepare the file for uploading
with open('shipments_import.csv', 'rb') as file:
files = {'file': ('shipments_import.csv', file, 'text/csv')}
response = requests.post(upload_url, headers=upload_headers, files=files)
# The API responds with the initial batch object
batch_object = response.json()
batch_id = batch_object["id"]
print(f"File upload submitted successfully! Batch ID: {batch_id}")
print(f"Initial Batch Response: {json.dumps(batch_object, indent=2)}")
Make sure shipments_import.csv is in your current directory.
curl -X POST "https://www.visiwise.co/v1/shipments/imports" \
-H "Authorization: Bearer YOUR_VISIWISE_API_KEY" \
-F "file=@shipments_import.csv"
Sample Response
The API will return a batch object with a status of processing.
{
"id": "556ec6ce-fa3b-4175-aa93-85e4871291b9",
"status": "processing",
"created_at": "2025-09-16T08:02:25.959Z",
"results": [
{
"id": "af3bb60c-68c8-48f3-99fa-dfffd15e79e4",
"reference": "ref-C006",
"tracking_type": "container",
"tracking_number": "MSDU8525700",
"carrier_scac": "MSCU",
"creation_status": "created",
"tracking_status": "processing",
"shipment_id": "6a3471d5-297d-4399-9962-6a0c2c554b23",
"name": "Coconuts & Apples",
"errors": [],
"warnings": [],
...
},
{
"id": "3f140007-fbb1-40dc-92d9-b8a96f31e8f6",
"reference": "ref-C007",
"tracking_type": "container",
"tracking_number": "MSNU5702988",
"carrier_scac": "MSCU",
"creation_status": "created",
"tracking_status": "processing",
"shipment_id": "a1c06601-5985-4a23-9467-fa9018b8d8a3",
"name": "Electronics Shipment",
"errors": [],
"warnings": [],
...
}
]
}
Step 5: Monitor the Import Status
Because the file is processed asynchronously, you need to poll the import status endpoint to know when it's finished. You can make GET requests to /v1/shipments/imports/{batch_id}.
The status field in the response will change from processing to completed or failed.
Asynchronous processing allows the API to accept your request immediately and handle the file in the background. This is much more reliable for large files. Polling is how your application can ask, "Are you done yet?"
- Python
- cURL
status_url = f"{BASE_URL}/api/v1/shipments/imports/{batch_id}"
while True:
print("Checking import status...")
response = requests.get(status_url, headers=headers)
batch_result = response.json()
status = batch_result.get("status")
print(f"Current Status: {status}")
# Exit the loop if the process is no longer running
if status in ["completed", "failed"]:
print("Import process finished!")
print(f"Final Batch Status: {json.dumps(batch_result, indent=2)}")
break
# Wait 10 seconds before checking again to avoid rate limiting
time.sleep(10)
Replace BATCH_ID with your batch ID to filter the shipments.
curl -X GET "https://www.visiwise.co/v1/shipments/imports/BATCH_ID" \
-H "Authorization: Bearer YOUR_VISIWISE_API_KEY" \
-H "Content-Type: application/json"
Sample Response
Once all requests are processed, the status will update to completed.
{
"id": "556ec6ce-fa3b-4175-aa93-85e4871291b9",
"status": "completed",
"created_at": "2025-09-16T08:02:25.959Z",
"results": [
{
"id": "af3bb60c-68c8-48f3-99fa-dfffd15e79e4",
"reference": "ref-C006",
"tracking_type": "container",
"tracking_number": "MSDU8525700",
"carrier_scac": "MSCU",
"creation_status": "created",
"tracking_status": "succeeded",
"shipment_id": "6a3471d5-297d-4399-9962-6a0c2c554b23",
"name": "Coconuts & Apples",
"errors": [],
"warnings": [
{
"code": "invalid_input",
"message": "[email protected] is not a valid member in this workspace",
"target": "assignees"
},
...
],
...
},
{
"id": "3f140007-fbb1-40dc-92d9-b8a96f31e8f6",
"reference": "ref-C007",
"tracking_type": "container",
"tracking_number": "MSNU5702988",
"carrier_scac": "MSCU",
"creation_status": "created",
"tracking_status": "succeeded",
"shipment_id": "a1c06601-5985-4a23-9467-fa9018b8d8a3",
"name": "Electronics Shipment",
"errors": [],
"warnings": [
{
"code": "invalid_input",
"message": "[email protected] is not a valid member in this workspace",
"target": "assignees"
},
...
],
...
}
]
}
Step 6: Review the Results
Once the batch status is completed, you can see which shipments were created successfully.
- To get a list of all shipments created from this batch, you can use the
GET /v1/shipmentsendpoint and filter by thebatch_id. - To review any rows that failed, check the
errorsarray in the final batch status object.
- Python
- cURL
# Use the batch_id to query for the newly created shipments
shipments_url = f"{BASE_URL}/api/v1/shipments"
params = {
"batch_id": batch_id
}
response = requests.get(shipments_url, headers=headers, params=params)
response = requests.get(shipments_url, headers=headers, params=params)
shipments = response.json().get("data")
print(f"Retrieved {len(shipments)} shipments for batch {batch_id}:")
print(json.dumps(shipments, indent=2))
Replace BATCH_ID with your batch ID to filter the shipments.
curl -X GET "https://www.visiwise.co/v1/shipments/?batch_id=BATCH_ID" \
-H "Authorization: Bearer YOUR_VISIWISE_API_KEY" \
-H "Content-Type: application/json"
Sample Response
The response will be a paginated list of Shipment objects, each containing comprehensive tracking data from all available sources.
{
"data": [
{
"id": "6a3471d5-297d-4399-9962-6a0c2c554b23",
"reference": "ref-C006"
"tracking_number": "MSDU8525700",
"tracking_type": "container",
"carrier_scac": "MSCU",
"last_process_status": "track_succeeded",
"last_process_failure_reason": null,
"data_status": "success",
"container_stage": null,
"custom_fields": {
"wdgpuzcr89": "PO-111"
},
"tracking": {
"tracking_freshness": "ok",
"pre": null,
"pol": null,
"pod": {
...
},
"pde": {
...
},
"containers_uri": "/api/v1/shipment/6a3471d5-297d-4399-9962-6a0c2c554b23/containers",
...
},
},
{
"id": "a1c06601-5985-4a23-9467-fa9018b8d8a3",
"reference": "ref-C007"
"tracking_number": "MSNU5702988",
"tracking_type": "container",
"carrier_scac": "MSCU",
"last_process_status": "track_succeeded",
"last_process_failure_reason": null,
"data_status": "success",
"container_stage": null,
"custom_fields": {
"wdgpuzcr89": "PO-222"
},
"tracking": {
"tracking_freshness": "ok",
"pre": {
...
},
"pol": {
...
},
"pod": {
...
},
"pde": {
...
},
"containers_uri": "/api/v1/shipment/a1c06601-5985-4a23-9467-fa9018b8d8a3/containers",
...
},
}
],
"pagination": {
...
}
}
Final Example Code
- Python
import requests
import json
BASE_URL = "https://www.visiwise.co"
API_KEY = "YOUR_VISIWISE_API_KEY"
# Headers for application/json requests.
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
# The endpoint for file uploads
upload_url = f"{BASE_URL}/api/v1/shipments/imports/file"
# Headers for multipart/form-data requests.
# Note: The 'requests' library sets the 'Content-Type' with the correct boundary automatically.
upload_headers = {
"Authorization": f"Bearer {API_KEY}"
}
# Prepare the file for uploading
with open('shipments_import.csv', 'rb') as file:
files = {'file': ('shipments_import.csv', file, 'text/csv')}
response = requests.post(upload_url, headers=upload_headers, files=files)
# The API responds with the initial batch object
batch_object = response.json()
batch_id = batch_object["id"]
print(f"File upload submitted successfully! Batch ID: {batch_id}")
print(f"Initial Batch Response: {json.dumps(batch_object, indent=2)}")
status_url = f"{BASE_URL}/api/v1/shipments/imports/{batch_id}"
while True:
print("Checking import status...")
response = requests.get(status_url, headers=headers)
batch_result = response.json()
status = batch_result.get("status")
print(f"Current Status: {status}")
# Exit the loop if the process is no longer running
if status in ["completed", "failed"]:
print("Import process finished!")
print(f"Final Batch Status: {json.dumps(batch_result, indent=2)}")
break
# Wait 10 seconds before checking again to avoid rate limiting
time.sleep(10)
# Use the batch_id to query for the newly created shipments
shipments_url = f"{BASE_URL}/api/v1/shipments"
params = {
"batch_id": batch_id
}
response = requests.get(shipments_url, headers=headers, params=params)
shipments = response.json().get("data")
print(f"Retrieved {len(shipments)} shipments for batch {batch_id}:")
print(json.dumps(shipments, indent=2))
Wrap-up
Congratulations! You have successfully imported multiple shipments into the Visiwise platform by uploading a file. You can now integrate this workflow into your applications to automate shipment tracking at scale.