Shipping Costs
Shipping Costs Guide
This guide explains how to calculate shipping costs for outbound orders using the Spreetail Channel Integration API.
Overview
The shipping cost calculation endpoint allows you to:
- Get accurate shipping cost estimates
- Compare different shipping options
- Calculate costs before order creation
- Optimize shipping decisions
Note:
/outbound-costremains available on API Hub for backward compatibility.
Endpoint
POST /outbound-cost
Full URL: https://api.spreetaileu.com/api/api/v1/outbound-cost
Authentication
This endpoint accepts either:
- Bearer token:
Authorization: Bearer <access_token> - ApiKey:
Authorization: ApiKey CLIENT_ID:CLIENT_SECRET
Request Structure
To calculate shipping costs, provide:
- Ship To: Destination country code using
shipTo - Ship From: Optional origin country code via
shipFrom(item-level) - Items: Array of items, each with:
shipTo(string): Destination country code (ISO 3166-1 alpha-2)shipFrom(string, optional): Origin country codesku(string): Product SKU identifierweight(number): Item weight in kilograms (minimum: 0.01, maximum: 10000)length(number): Item length in centimeters (minimum: 0.01, maximum: 10000)width(number): Item width in centimeters (minimum: 0.01, maximum: 10000)height(number): Item height in centimeters (minimum: 0.01, maximum: 10000)
Required Fields
| Field | Type | Description |
|---|---|---|
items[].shipTo | string | Destination country code (ISO 3166-1 alpha-2, exactly 2 characters). Required per item. |
items[].shipFrom | string | Optional origin country code. If omitted: UK destinations default to UK, non-UK destinations default to DE. |
items | array | Array of items to ship (minimum 1 item required) |
items[].sku | string | Product SKU identifier |
items[].weight | number | Item weight in kilograms (0.01 - 10000) |
items[].length | number | Item length in centimeters (0.01 - 10000) |
items[].width | number | Item width in centimeters (0.01 - 10000) |
items[].height | number | Item height in centimeters (0.01 - 10000) |
Example Request: Single Item
{
"items": [
{
"shipTo": "DE",
"shipFrom": "DE",
"sku": "PROD-12345",
"weight": 2.5,
"length": 20,
"width": 15,
"height": 10
}
]
}Example Request: Multiple Items with Different SKUs
When calculating shipping for an order with multiple different products, include each item with its unique SKU:
{
"items": [
{
"sku": "PROD-12345",
"shipTo": "GB",
"shipFrom": "DE",
"weight": 2.5,
"length": 20,
"width": 15,
"height": 10
},
{
"sku": "PROD-67890",
"shipTo": "FR",
"weight": 1.2,
"length": 15,
"width": 10,
"height": 5
},
{
"sku": "WIDGET-XYZ",
"shipTo": "FR",
"weight": 0.8,
"length": 12,
"width": 8,
"height": 6
}
]
}Multiple SKUs: Each item in the
itemsarray is routed independently using item-levelshipToand optionalshipFrom.
Code Examples
Python
import requests
def calculate_shipping_cost(access_token, cost_data):
"""Calculate shipping cost for an order"""
url = "https://api.spreetaileu.com/api/api/v1/outbound-cost"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
response = requests.post(url, headers=headers, json=cost_data)
response.raise_for_status()
return response.json()
# Example usage: Single item
cost_request_single = {
"items": [
{
"shipTo": "DE",
"shipFrom": "DE",
"sku": "PROD-12345",
"weight": 2.5,
"length": 20,
"width": 15,
"height": 10
}
]
}
# Example usage: Multiple items with different SKUs
cost_request_multiple = {
"items": [
{
"sku": "PROD-12345",
"shipTo": "GB",
"shipFrom": "DE",
"weight": 2.5,
"length": 20,
"width": 15,
"height": 10
},
{
"sku": "PROD-67890",
"shipTo": "FR",
"weight": 1.2,
"length": 15,
"width": 10,
"height": 5
},
{
"sku": "WIDGET-XYZ",
"shipTo": "FR",
"weight": 0.8,
"length": 12,
"width": 8,
"height": 6
}
]
}
result = calculate_shipping_cost("your-access-token", cost_request_multiple)
# Display eligible carriers by SKU
if result['success']:
for sku_result in result['data']['items']:
print(f"\nSKU: {sku_result['sku']}")
print("Available shipping options:")
for carrier in sku_result['eligible_carriers']:
print(f" {carrier['carrier_name']} ({carrier['service_name']}): "
f"{carrier['cost']} {carrier['currency']} - "
f"{carrier['estimated_delivery_days']} days")
if sku_result['rejected_carriers']:
print("Unavailable carriers:")
for carrier in sku_result['rejected_carriers']:
print(f" {carrier['carrier_name']}: {carrier['reason']}")JavaScript/Node.js
async function calculateShippingCost(accessToken, costData) {
const url = 'https://api.spreetaileu.com/api/api/v1/outbound-cost';
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(costData)
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Shipping cost calculation failed: ${error.error || response.statusText}`);
}
return await response.json();
}
// Example usage: Single item
const costRequestSingle = {
items: [
{
shipTo: 'DE',
shipFrom: 'DE',
sku: 'PROD-12345',
weight: 2.5,
length: 20,
width: 15,
height: 10
}
]
};
// Example usage: Multiple items with different SKUs
const costRequestMultiple = {
items: [
{
sku: 'PROD-12345',
shipTo: 'GB',
shipFrom: 'DE',
weight: 2.5,
length: 20,
width: 15,
height: 10
},
{
sku: 'PROD-67890',
shipTo: 'FR',
weight: 1.2,
length: 15,
width: 10,
height: 5
},
{
sku: 'WIDGET-XYZ',
shipTo: 'FR',
weight: 0.8,
length: 12,
width: 8,
height: 6
}
]
};
calculateShippingCost('your-access-token', costRequestMultiple)
.then(result => {
if (result.success) {
result.data.items.forEach((skuResult) => {
console.log(`\nSKU: ${skuResult.sku}`);
console.log('Available shipping options:');
skuResult.eligible_carriers.forEach(carrier => {
console.log(
`${carrier.carrier_name} (${carrier.service_name}): ` +
`${carrier.cost} ${carrier.currency} - ` +
`${carrier.estimated_delivery_days} days`
);
});
if (skuResult.rejected_carriers.length > 0) {
console.log('Unavailable carriers:');
skuResult.rejected_carriers.forEach(carrier => {
console.log(`${carrier.carrier_name}: ${carrier.reason}`);
});
}
});
}
})
.catch(error => console.error('Error:', error));Response Format
Success Response (200)
{
"success": true,
"data": {
"items": [
{
"sku": "PROD-12345",
"eligible_carriers": [
{
"carrier_name": "DHL",
"service_name": "Express",
"cost": 12.5,
"currency": "EUR",
"estimated_delivery_days": 2,
"tracking_available": true
}
],
"rejected_carriers": [
{
"carrier_name": "Royal Mail",
"service_name": "Standard",
"reason": "Destination not supported"
}
]
}
]
}
}Response Fields
| Field | Type | Description |
|---|---|---|
data.items | array | Results grouped by input SKU |
data.items[].sku | string | Input SKU |
data.items[].eligible_carriers | array | Carriers that can fulfill that SKU shipment |
data.items[].eligible_carriers[].carrier_name | string | Name of the shipping carrier |
data.items[].eligible_carriers[].service_name | string | Service level name |
data.items[].eligible_carriers[].cost | number | Shipping cost |
data.items[].eligible_carriers[].currency | string | Currency code (ISO 4217) |
data.items[].rejected_carriers | array | Carriers rejected for that SKU |
data.items[].rejected_carriers[].carrier_name | string | Name of the shipping carrier |
data.items[].rejected_carriers[].reason | string | Reason for rejection |
Use Cases
1. Compare Shipping Options
def compare_shipping_options(access_token, destination, items):
"""Compare different shipping options for a shipment"""
cost_request = {
"shipTo": destination,
"items": items
}
result = calculate_shipping_cost(access_token, cost_request)
if result['success']:
eligible = result['data']['items'][0]['eligible_carriers'] if result['data']['items'] else []
# Sort by cost
sorted_by_cost = sorted(eligible, key=lambda x: x['cost'])
# Sort by delivery time
sorted_by_time = sorted(eligible, key=lambda x: x['estimated_delivery_days'])
return {
"cheapest": sorted_by_cost[0] if sorted_by_cost else None,
"fastest": sorted_by_time[0] if sorted_by_time else None,
"all_options": eligible
}
return None
# Usage: Multiple items with different SKUs
items = [
{
"sku": "PROD-12345",
"weight": 2.5,
"length": 20,
"width": 15,
"height": 10
},
{
"sku": "PROD-67890",
"weight": 1.2,
"length": 15,
"width": 10,
"height": 5
},
{
"sku": "WIDGET-XYZ",
"weight": 0.8,
"length": 12,
"width": 8,
"height": 6
}
]
options = compare_shipping_options("your-access-token", "DE", items)
if options:
print(f"Cheapest: {options['cheapest']['carrier_name']} - {options['cheapest']['cost']} EUR")
print(f"Fastest: {options['fastest']['carrier_name']} - {options['fastest']['estimated_delivery_days']} days")2. Validate Shipping Feasibility
def check_shipping_feasibility(access_token, destination, items):
"""Check if shipping is possible to a destination"""
cost_request = {
"shipTo": destination,
"items": items
}
result = calculate_shipping_cost(access_token, cost_request)
if result['success']:
first_item = result['data']['items'][0] if result['data']['items'] else {'eligible_carriers': [], 'rejected_carriers': []}
eligible_count = len(first_item['eligible_carriers'])
rejected_count = len(first_item['rejected_carriers'])
return {
"feasible": eligible_count > 0,
"eligible_carriers": eligible_count,
"rejected_carriers": rejected_count,
"options": first_item['eligible_carriers']
}
return {"feasible": False, "error": "Calculation failed"}
# Usage
feasibility = check_shipping_feasibility("your-access-token", "DE", items)
if feasibility['feasible']:
print(f"Shipping available via {feasibility['eligible_carriers']} carrier(s)")
else:
print("Shipping not available to this destination")Important Notes
Endpoint Enablement
- No endpoint-specific enablement is required for
/outbound-cost
Authentication
- Use either:
Authorization: Bearer <access_token>Authorization: ApiKey CLIENT_ID:CLIENT_SECRET
Country Code
shipTomust be a valid ISO 3166-1 alpha-2 country code- Exactly 2 characters (e.g., "DE", "GB", "US")
- Case-sensitive (use uppercase)
Ship From Defaults
- Pass
shipFromper item when you need a specific origin - If omitted, fallback is destination-aware:
- UK destination -> UK
- non-UK destination -> DE
Weight and Dimensions
- Weight: Must be in kilograms (minimum: 0.01, maximum: 10000)
- Dimensions: Must be in centimeters (minimum: 0.01, maximum: 10000)
- All dimensions are required for each item
- Providing accurate measurements improves cost calculation accuracy
Items Array
- At least one item is required
- Each item must include all required fields:
sku,weight,length,width,height - Multiple items in one request represent a combined shipment
Error Handling
Endpoint Not Enabled (403)
If the endpoint is not enabled for your account:
{
"success": false,
"error": "Unauthorized"
}Solution: Contact [email protected] to enable the feature.
Invalid Request (400)
{
"success": false,
"error": "Invalid request (missing fields, invalid values)"
}Solution: Verify all required fields are present and values are within valid ranges.
Authentication Error (401)
{
"success": false,
"error": "Unauthorized"
}Solution: Provide a valid Bearer token or ApiKey credentials.
Best Practices
- Calculate Before Order Creation: Get shipping costs before finalizing orders
- Cache Results: Cache shipping costs for similar destinations/items
- Handle Errors: Implement fallback for when endpoint is unavailable
- Compare Options: Use the response to compare multiple carrier options
- Consider Delivery Time: Factor in estimated delivery days when selecting carriers
- Validate Dimensions: Ensure weight and dimensions are accurate for better cost estimates
Related Endpoints
POST /outbound- Create order (use shipping cost information in order)GET /order/{referenceNumber}- Check order status and actual shipping details
Updated 29 days ago
