Migration workflow
Migrate references, identifiers, tracking data and notifications to TimeToCargo API v2
Follow this workflow alongside the guide for your provider. This page covers the shared steps, while each provider guide identifies the operations and fields to replace. Full request and response schemas are in the API reference.
1. Preserve references and ID mappings
One TimeToCargo record tracks one container, bill of lading (bl) or booking (bk) reference. A bill of lading or booking result can contain several containers. Former-provider IDs do not transfer. After creating tracking records, save a mapping between old and new IDs in your database.
| Value | Purpose | What to store |
|---|---|---|
| Container, bill of lading or booking reference | The reference used to request carrier data | Save the reference, its type and carrier SCAC. These values are required for the request. |
| Former-provider ID | A link to the former record in your application | Retain the source ID and map it to the new tracking ID once the result is available. |
data.task_id | A temporary batch task ID | Keep it until results are retrieved. Do not use it to update or stop tracking. |
data.tracking_metadata.id | A permanent tracking ID | Store it alongside the source ID. The same ID appears as data.data[].id in the list response. |
containers[].number | A container number within the result | Store it with the new tracking ID if your system manages individual containers within one document. |
2. Configure authentication and request parameters
Create a key in your TimeToCargo account. The API base URL is https://tracking.timetocargo.com/v2. Send the key in the api_key query parameter of every request, including batch tasks and webhook management. The former provider's key cannot be reused. See authentication for access rules.
Use GET /v2/tracking for one reference and POST /v2/tracking/batch for several.
| Data | GET /v2/tracking | POST /v2/tracking/batch |
|---|---|---|
| API key | Query parameter api_key | The same api_key query parameter |
| Reference | Query parameter value | JSON body field tracked_items[].track_number.value |
| Reference type | Query parameter type: container, bl or bk | Body field tracked_items[].track_number.type with the same values |
| Carrier | Query parameter company | JSON body field tracked_items[].company |
| Route request | Query parameter need_route=true | The same need_route=true query parameter for the batch request |
| Tracking label | After obtaining the permanent ID, call PATCH /v2/shipments/{id} with note | Obtain the permanent ID from the task result, then call the same PATCH |
Reference, type and carrier are required. Find the carrier SCAC through GET /v2/companies and check support for the required reference type in cn, bl or bk. Map another provider's numeric ID or internal code to this directory first. Automatic carrier detection with company=AUTO is available only for type=container. Supply a SCAC for bills of lading and bookings.
3. Configure webhooks and retain history
If you need notifications from the first updates, create webhooks through POST /v2/webhooks before importing references. Webhooks are configured for the account, so do not send callback_url in each tracking request. Configure event_types, a new secret, signature verification and duplicate-delivery handling using the webhook guide.
GET /v2/webhook-notifications contains notification delivery records. Store received notifications in your system to maintain your own update archive. Export former-provider history, tags, last free pickup dates, fees, AIS measurements and custom fields separately.
4. Separate tracking initiation from stored data retrieval
| Action | Operation | Required application change |
|---|---|---|
| Start tracking one reference and receive a response | GET /v2/tracking | Pass the reference, type and carrier. The request may activate tracking and consume a credit. |
| Start background processing for 1–500 references | POST /v2/tracking/batch | Send the tracked_items array and save the returned data.task_id. |
| Retrieve a task result | GET /v2/tracking/batch?task_id=… | Wait for data.status: "PROCESSED", then process each entry in data.results[]. |
| Retrieve stored tracking records | GET /v2/shipments?page=1&limit=50&status=ACTIVE | Iterate over data.data[] and fetch pages through data.meta.totalPages. Use status=ARCHIVED for archived records. |
| Retrieve a stored route | GET /v2/shipments?need_route=true | Read tracked_item.data.data.route_info from the selected record. Handle a possible null. |
| Edit a label | PATCH /v2/shipments/{id} | Send note with up to 40 characters. An empty string clears it. |
| Stop tracking records | DELETE /v2/shipments | Send an array of new IDs in the body field shipmentIds. Check archiving and deletion rules in the lifecycle guide. |
To retrieve one stored record, find its new ID in the /v2/shipments pages. There is no individual GET /v2/shipments/{id} or list filter by ID. Do not replace stored data retrieval with another /v2/tracking request: these operations have different purposes and credit rules.
For example, to request one container:
GET https://tracking.timetocargo.com/v2/tracking?api_key=YOUR_API_KEY&value=MSCU1234567&type=container&company=MSCUThe two batch responses
Send POST /v2/tracking/batch?api_key=YOUR_API_KEY with this body:
{
"tracked_items": [
{
"track_number": {
"type": "container",
"value": "MSCU1234567"
},
"company": "MSCU"
}
]
}The creation response contains the task ID. Retrieve shipment data with a separate request:
POST /v2/tracking/batch response
{
"success": true,
"status": "OK",
"data": {
"task_id": "22222222-2222-4222-8222-222222222222"
}
}Then call GET /v2/tracking/batch?api_key=YOUR_API_KEY&task_id=22222222-2222-4222-8222-222222222222. The completed-task example below includes illustrative container data, events and a permanent tracking ID.
{
"success": true,
"status": "OK",
"data": {
"task_id": "22222222-2222-4222-8222-222222222222",
"status": "PROCESSED",
"results": [
{
"success": true,
"status": "OK",
"status_description": "Tracking information found",
"request": {
"track_number": {
"type": "container",
"value": "MSCU1234567"
},
"company": "MSCU"
},
"data": {
"summary": {
"origin": {
"location": null,
"terminal": null,
"date": null
},
"pol": {
"location": 0,
"terminal": null,
"date": "2026-10-01T12:00:00"
},
"pod": {
"location": 1,
"terminal": null,
"date": "2026-10-12T08:00:00"
},
"destination": {
"location": null,
"terminal": null,
"date": null
},
"company": {
"name": "MSC",
"full_name": "Mediterranean Shipping Company",
"url": "https://www.msc.com/",
"scacs": ["MEDU", "MSCU"]
}
},
"locations": [
{
"id": 0,
"name": "Singapore",
"state": null,
"terminal": null,
"country": "Singapore",
"lat": 1.264,
"lng": 103.84
},
{
"id": 1,
"name": "Rotterdam",
"state": null,
"terminal": null,
"country": "Netherlands",
"lat": 51.95,
"lng": 4.14
}
],
"terminals": [],
"containers": [
{
"number": "MSCU1234567",
"type": "40' High Cube Dry",
"events": [
{
"location": 1,
"terminal": null,
"status": "Vessel arrival",
"status_code": "VAD",
"date": "2026-10-12T08:00:00",
"actual": false,
"vessel": "EXAMPLE VESSEL",
"voyage": "126E"
},
{
"location": 0,
"terminal": null,
"status": "Loaded",
"status_code": "CLL",
"date": "2026-10-01T12:00:00",
"actual": true,
"vessel": "EXAMPLE VESSEL",
"voyage": "126E"
}
]
}
],
"route_info": null,
"shipment_status": "IN_TRANSIT",
"references": {
"booking_numbers": ["BOOKING123"],
"bill_of_lading_numbers": ["MEDU1234567"]
},
"tracking_metadata": {
"id": "11111111-1111-4111-8111-111111111111",
"end_date": null,
"status": "ACTIVE",
"note": null,
"created_at": "2026-10-03T09:00:00.000Z",
"updated_at": "2026-10-03T09:00:00.000Z"
}
}
}
]
}
}Task statuses are CREATED for waiting, HANDLING for processing, and PROCESSED for completed processing. After PROCESSED, check success and status for each entry in data.results[]. Task completion does not mean data was found for every reference.
Match each result to its submitted reference using results[].request.track_number. Save the permanent results[].data.tracking_metadata.id when data and tracking_metadata are not null. Results are retained for up to 6 hours. Save them after task completion; see batch tracking for a polling example with bounded retries.
5. Update response handling
In GET /v2/tracking, shipment data is under data. In GET /v2/shipments, first select a record from data.data[], then access its fields using the paths in the third column.
| Data | In the GET /v2/tracking response | In the selected data.data[] record |
|---|---|---|
| Shipment progress | data.shipment_status | tracked_item.data.data.shipment_status |
| Carrier and main route points | data.summary | tracked_item.data.data.summary |
| Containers and events | data.containers[].events[] | tracked_item.data.data.containers[].events[] |
| Event locations | data.locations[] | tracked_item.data.data.locations[] |
| Terminals | data.terminals[] | tracked_item.data.data.terminals[] |
| Route and current position | data.route_info | tracked_item.data.data.route_info |
| Tracking ID | data.tracking_metadata.id | id |
| Subscription status | data.tracking_metadata.status | status: ACTIVE or ARCHIVED |
Check the statuses separately:
successandstatusreport the API request result. In a list, also check each record'stracked_item.data.successandtracked_item.data.status.- Batch
data.statusreports whether task processing has finished. ACTIVEandARCHIVEDdescribe the tracking subscription.shipment_statusdescribes shipment progress, such asIN_TRANSITorDELIVERED.
For events, use status_code, date and actual. Events run newest to oldest when every date is present; otherwise, the carrier’s order is preserved. Do not match events across providers by array index.
For example, CLL means loading at the origin port and CLT means transshipment loading. Resolve event.location to the corresponding id in locations, and event.terminal through terminals. actual=true means the event has occurred, while false means it is expected. A null value indicates missing information. Do not automatically treat a timestamp without a time zone as UTC.
Request route data with need_route=true. If shipment information is insufficient to construct a route, route_info may be null. Coordinates in route_info use [latitude, longitude] order. Reverse them to [longitude, latitude] for GeoJSON.
An empty result does not mean delivery. Distinguish missing data, carrier errors and completed shipments. Handle retries and HTTP 429 using the error guide, respecting Retry-After when present.
6. Validate with a small sample
- Export references, types, carriers and source ID relationships. You can use the TimeToCargo trial period to test the migration. Account for tracking allowance usage when submitting requests.
- Test a container, a bill of lading or booking with several containers, missing data and a completed shipment.
- Compare responses using your provider's examples. Check field paths, event codes, planned and actual dates, and coordinates. Predictions can differ between providers.
- Test pagination, individual batch failures, missing routes and duplicate webhook deliveries.
- Switch data retrieval and notifications to TimeToCargo. Keep your ID mapping and a way to restore the former integration. After validation, stop former subscriptions: TimeToCargo does not cancel them automatically.
Last updated on