Documentation Index
Fetch the complete documentation index at: https://docs.crbtrack.com/llms.txt
Use this file to discover all available pages before exploring further.
This guide walks through the complete shipping workflow from order creation to delivery confirmation.
Workflow Overview
Step 1: Create Orders
When a customer places an order, create a parcel in CrossBorderly:
async function createShipment(order) {
const response = await fetch('https://api.crbtrack.com/api/v1/orders/create', {
method: 'POST',
headers: {
'X-API-Key': process.env.CROSSBORDERLY_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
idempotencyKey: `order-${order.id}`,
externalOrderId: order.id,
sender: {
fullName: 'Your Company Name',
phone: '+1 305-555-0123',
address: {
line1: '1234 Warehouse St',
city: 'Miami',
state: 'FL',
zipCode: '33101',
country: 'US'
}
},
receiver: {
fullName: order.customer.name,
phone: order.customer.phone,
email: order.customer.email,
nationalId: order.customer.nationalId,
address: {
line1: order.shippingAddress.line1,
city: order.shippingAddress.city,
province: order.shippingAddress.province,
zipCode: order.shippingAddress.zipCode,
country: order.shippingAddress.country
}
},
parcelDetails: {
weightLbs: order.totalWeight,
declaredValue: order.totalValue
},
products: order.items.map(item => ({
description: item.name,
quantity: item.quantity,
unitFobValue: item.price,
sku: item.sku
}))
})
});
const data = await response.json();
// Store the tracking number in your database
await db.orders.update(order.id, {
trackingNumber: data.parcel.trackingNumber,
labelUrl: data.parcel.labelUrl
});
return data;
}
Step 2: Print Labels
Download and print the shipping label:
async function downloadLabel(trackingNumber) {
const response = await fetch(
`https://api.crbtrack.com/api/v1/labels/${trackingNumber}/download`,
{
headers: { 'X-API-Key': process.env.CROSSBORDERLY_API_KEY }
}
);
// For web: Create download link
const blob = await response.blob();
const url = URL.createObjectURL(blob);
// For server: Save to file
const buffer = await response.arrayBuffer();
await fs.writeFile(`./labels/${trackingNumber}.pdf`, Buffer.from(buffer));
}
Step 3: Submit Manifest
Once you have a batch of parcels ready to ship, submit them as a manifest:
async function submitShipmentManifest(shipment) {
const parcels = await db.parcels.findByShipment(shipment.id);
const response = await fetch('https://api.crbtrack.com/api/v1/manifests/submit', {
method: 'POST',
headers: {
'X-API-Key': process.env.CROSSBORDERLY_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
idempotencyKey: `manifest-${shipment.id}`,
awbNumber: shipment.awbNumber,
flightNumber: shipment.flightNumber,
flightDate: shipment.flightDate,
originAirport: 'MIA',
destinationAirport: shipment.destination,
carrier: shipment.carrier,
country: shipment.country,
parcels: parcels.map(p => ({
trackingNumber: p.trackingNumber,
bagCode: p.bagCode
}))
})
});
const data = await response.json();
if (data.notFound?.length > 0) {
console.warn('Some parcels not found:', data.notFound);
}
return data;
}
Step 4: Track Parcels
Real-time via Webhooks (Recommended)
Configure webhooks to receive status updates automatically:
// Webhook endpoint
app.post('/webhooks/crossborderly', (req, res) => {
const event = req.body;
switch (event.event) {
case 'parcel.status_changed':
handleStatusChange(event.data);
break;
case 'parcel.delivered':
handleDelivery(event.data);
break;
case 'parcel.exception':
handleException(event.data);
break;
}
res.status(200).send('OK');
});
async function handleStatusChange(data) {
const order = await db.orders.findByTracking(data.trackingNumber);
await db.orders.update(order.id, {
shippingStatus: data.newStatus,
lastUpdate: data.timestamp
});
// Notify customer
await sendCustomerEmail(order.customer.email, {
subject: 'Your order has been updated',
status: data.newStatus,
trackingUrl: `https://track.crbtrack.com/${data.trackingNumber}`
});
}
Polling (Fallback)
For batch status checks:
async function syncTrackingStatus(trackingNumbers) {
const response = await fetch('https://api.crbtrack.com/api/v1/tracking/batch', {
method: 'POST',
headers: {
'X-API-Key': process.env.CROSSBORDERLY_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ trackingNumbers, includeHistory: false })
});
const data = await response.json();
for (const result of data.results) {
await db.orders.update({ trackingNumber: result.trackingNumber }, {
shippingStatus: result.status
});
}
}
Step 5: Handle Exceptions
Build exception handling into your workflow:
async function handleShippingException(data) {
const order = await db.orders.findByTracking(data.trackingNumber);
switch (data.exceptionType) {
case 'CUSTOMS_HOLD':
// May need additional documentation
await notifyOpsTeam(order, 'Customs hold - review required');
break;
case 'DELIVERY_FAILED':
// Schedule retry or contact customer
await scheduleDeliveryRetry(order);
await sendDeliveryFailureEmail(order.customer.email);
break;
case 'ADDRESS_ISSUE':
// Address correction needed
await requestAddressCorrection(order);
break;
case 'RETURN_TO_SENDER':
// Initiate refund process
await initiateRefund(order);
break;
}
}
Best Practices
- Create orders in batches during off-peak hours
- Submit manifests when you have 50+ parcels ready
- Use batch tracking instead of individual calls
- Always use idempotency keys for POST requests
- Implement retry logic with exponential backoff
- Store raw API responses for troubleshooting
Complete Integration Checklist