Terminal49
Переход с Terminal49 на Cargotime API v2: ключи доступа, запросы и обработка ответов
Руководство описывает переход с Terminal49 API v2 на Cargotime API v2. Terminal49 использует JSON:API с отдельными записями запроса на отслеживание, перевозки и контейнера. Ниже показано, как запустить отслеживание и сохранить связи между этими записями.
Общий порядок переноса номеров и настройки уведомлений приведён в порядке перехода. Полные схемы Cargotime — в справочнике API.
Аутентификация
Terminal49 передаёт ключ в заголовке Authorization: Token …. Базовый адрес Terminal49 — https://api.terminal49.com/v2. Для запросов с телом используйте Content-Type: application/json. Уберите оболочку JSON:API data.attributes и передавайте поля по новой схеме.
Для перехода на Cargotime:
- Создайте ключ в личном кабинете Cargotime.
- Замените базовый адрес на
https://tracking.cargotime.ru/v2. Например, полный адрес запроса отслеживания —https://tracking.cargotime.ru/v2/tracking. - Передавайте новый ключ в параметре URL
api_keyкаждого запроса, включая пакетные задачи и управление вебхуками. Ключи и токены прежнего сервиса не подходят.
Правила использования ключа и ограничения запросов — в разделе аутентификации.
Отслеживания и идентификаторы
| Terminal49 | Cargotime | Что изменить |
|---|---|---|
tracking_request | Временная задача пакетной обработки | Используйте задачу только для получения результата запуска. После её завершения сохраните постоянный ID отслеживания, а историю tracking_request выгрузите отдельно. |
shipment | Запись отслеживания и данные перевозки | Для каждого отслеживаемого номера сохраните новый ID. Контейнеры по коносаменту или букингу будут находиться внутри результата этой записи. |
container | containers[] | Находите контейнер по containers[].number. Отдельного постоянного ID контейнера и методов управления им здесь нет. |
transport_event | containers[].events[] | Получайте события из массива выбранного контейнера. Обновите обработку кодов, фактических и плановых дат по таблицам ниже. |
Соответствие операций
| Terminal49 | Cargotime | Что изменить |
|---|---|---|
POST /tracking_requests | POST /v2/tracking/batch → GET /v2/tracking/batch | Отправьте номера в пакетном запросе, получите результаты задачи и сохраните постоянные ID отслеживаний. |
GET /tracking_requests/{id} | GET /v2/tracking/batch?task_id=… (частично) | Проверяйте задачу до PROCESSED, затем используйте ID из data.results[].data.tracking_metadata.id. Задача хранится ограниченное время. |
GET /tracking_requests | Нет прямого аналога | Храните список отправленных задач и их результатов в своём журнале импорта. Метода получения всех задач нет. |
GET /shipments, GET /containers | GET /v2/shipments | Получайте страницы отслеживаний. Контейнеры каждой записи находятся в tracked_item.data.data.containers[]. |
GET /shipments/{id}, GET /containers/{id} | GET /v2/shipments | Найдите запись по сохранённому новому ID в страницах списка. Если нужен конкретный контейнер, выберите его по номеру внутри записи. |
GET /containers/{id}/transport_events | GET /v2/shipments → containers[].events[] | Получайте события выбранного контейнера из сохранённой записи. Отдельного метода со своей постраничной выдачей событий нет. |
PATCH /tracking_requests/{id} | PATCH /v2/shipments/{id} (частично) | Перенесите ref_number в note, если он укладывается в 40 символов. Изменить номер перевозчика или SCAC через этот метод нельзя. |
GET /shipping_lines | GET /v2/companies | Найдите перевозчика по SCAC и проверьте поддержку нужного типа номера в cn, bl, bk. |
PATCH /shipments/{id}/stop_tracking, PATCH /shipments/{id}/resume_tracking | DELETE /v2/shipments / новый запуск | Для остановки передайте новые ID в shipmentIds. Повторную активацию выполняйте запросом отслеживания с учётом жизненного цикла. |
/webhooks, /webhook_notifications | /v2/webhooks, /v2/webhook-notifications | Создайте вебхуки заново и обновите проверку подписи и разбор уведомлений. Журнал доставок доступен через /v2/webhook-notifications. |
Параметры запроса
| Terminal49 | Cargotime | Что изменить |
|---|---|---|
data.attributes.request_number | tracked_items[].track_number.value | Передайте request_number в tracked_items[].track_number.value. Уберите оболочку JSON:API data.attributes. |
data.attributes.request_type | tracked_items[].track_number.type | Оставьте container без изменения, замените bill_of_lading на bl, booking_number на bk. |
data.attributes.scac | tracked_items[].company | Проверьте SCAC через GET /v2/companies и передайте его в tracked_items[].company. |
auto_detect_vocc_scac | company=AUTO (частично) | Для автоматического определения перевозчика передайте company: "AUTO" только с типом container. Для коносамента и букинга укажите SCAC. |
POST: ref_numbers[] / initial_custom_fields, PATCH: ref_number | note + ваша система | После получения ID сохраните одну подпись до 40 символов в note. Массив номеров и произвольные поля сохраните в своей базе. |
include / filter / page | page / limit / status / need_route | Используйте page, limit и status для списка, need_route=true для маршрута. Удалите include и обновите обработку связей: массива included нет. |
Поля ответа
В ответе GET /v2/shipments выберите запись из data.data[]. Пути, начинающиеся с tracked_item, указаны относительно этой записи. Контейнеры находятся в tracked_item.data.data.containers[], события — в events[] каждого контейнера. В ответе GET /v2/tracking данные перевозки находятся сразу в data.
| Terminal49 | Cargotime | Как обработать ответ |
|---|---|---|
data.id у tracking_request | data.task_id (частично) | Не используйте task_id как постоянный ID. Получите результат задачи и сохраните data.results[].data.tracking_metadata.id. |
attributes.status: pending / created / failed | data.status + results[].success / status | Проверяйте data.status задачи, затем success и status каждого результата. PROCESSED означает завершение обработки, но не успех всех номеров. |
relationships.tracked_object.data | results[].data.tracking_metadata.id | Сохраните связь исходного tracked_object с новым постоянным ID. Новый ответ не содержит объекта JSON:API relationships. |
container.attributes.number | tracked_item.data.data.containers[].number | Получайте номер из containers[].number. При нескольких контейнерах выбирайте нужный элемент по номеру. |
transport_event.attributes.event | containers[].events[].status_code / actual | Обрабатывайте status_code и actual раздельно. Например, погрузка в порту отправления — CLL, при перегрузке — CLT. |
transport_event.attributes.timestamp / timezone / voyage_number | containers[].events[].date / voyage | Получайте дату события из date, рейс из voyage. При сравнении со старым timestamp учитывайте timezone. Не используйте время создания записи как дату события. |
pickup_lfd / holds_at_pod_terminal / fees_at_pod_terminal | Нет прямого аналога | Сохраните последний бесплатный день вывоза, ограничения выдачи и сборы отдельно. Эти сведения нельзя получить из общего shipment_status. |
Примеры ответов
В каждой паре подписаны ответы прежнего сервиса и Cargotime. Большие JSON-примеры можно раскрыть отдельно от таблиц сопоставления. Это сокращённые примеры с условными данными. Над каждым JSON указан путь к показанной части ответа. Пути в следующей таблице начинаются от этой части.
Запрос на отслеживание и фоновая задача
Terminal49 — POST /tracking_requests
Ответ, сокращённо.
{
"data": {
"id": "33333333-3333-4333-8333-333333333333",
"type": "tracking_request",
"attributes": {
"request_number": "MSCU1234567",
"request_type": "container",
"scac": "MSCU",
"ref_numbers": ["Order 123"],
"status": "pending"
},
"relationships": {
"tracked_object": {
"data": null
}
}
}
}Cargotime — POST /v2/tracking/batch
Ответ, сокращённо.
{
"success": true,
"status": "OK",
"data": {
"task_id": "22222222-2222-4222-8222-222222222222"
}
}Как сопоставить
| Terminal49 | Cargotime | Что изменить |
|---|---|---|
data.id = "33333333-3333-4333-8333-333333333333" | data.task_id = "22222222-2222-4222-8222-222222222222" | Исходный ID постоянный, а task_id временный. Дождитесь результата задачи, чтобы получить постоянный ID отслеживания. |
data.attributes.request_type = "container" | Нет прямого аналога | Тип передаётся при запуске в tracked_items[].track_number.type. Краткий ответ на запуск задачи его не повторяет. |
data.type = "tracking_request" | Нет прямого аналога | Удалите обработку JSON:API data.type. Тип номера задаётся отдельно и принимает container, bl или bk. |
data.attributes.ref_numbers = ["Order 123"] | Нет прямого аналога | Сохраните подпись отдельным PATCH /v2/shipments/{id} после получения постоянного ID. В ответе на запуск задачи note ещё нет. |
Ответ на запуск содержит только ID задачи. После PROCESSED получите постоянный ID из data.results[].data.tracking_metadata.id и используйте его для поиска записи в списке и изменения подписи.
Контейнер, связь с перевозкой и тип оборудования
Terminal49 — GET /containers/{id}
Фрагмент: data.
{
"id": "33333333-3333-4333-8333-333333333333",
"type": "container",
"attributes": {
"number": "MSCU1234567",
"current_status": "on_ship",
"ref_numbers": ["Order 123"],
"equipment_length": 40,
"equipment_height": "high_cube",
"equipment_type": "dry"
},
"relationships": {
"shipment": {
"data": {
"id": "66666666-6666-4666-8666-666666666666",
"type": "shipment"
}
}
}
}Cargotime — GET /v2/shipments
Фрагмент: data.data[0].
{
"id": "11111111-1111-4111-8111-111111111111",
"status": "ACTIVE",
"note": "Order 123",
"track_number": "MSCU1234567",
"tracked_item": {
"track_number": "MSCU1234567",
"track_number_type": "container",
"data": {
"success": true,
"status": "OK",
"data": {
"shipment_status": "IN_TRANSIT",
"containers": [
{
"number": "MSCU1234567",
"type": "40' High Cube Dry"
}
]
}
}
}
}Как сопоставить
| Terminal49 | Cargotime | Что изменить |
|---|---|---|
attributes.number = "MSCU1234567" | tracked_item.data.data.containers[0].number = "MSCU1234567" | Номер контейнера не меняется. Используйте его для выбора элемента в containers[]. |
id = "33333333-3333-4333-8333-333333333333" | id = "11111111-1111-4111-8111-111111111111" | Свяжите ID контейнера Terminal49 с новым ID отслеживания и номером контейнера. Один результат по документу может включать несколько контейнеров. |
relationships.shipment.data.id = "66666666-6666-4666-8666-666666666666" | Нет прямого аналога | Сохраните исходный ID родительского shipment в своей таблице связей. Отдельное поле с этим ID в новом ответе отсутствует. |
attributes.current_status = "on_ship" | tracked_item.data.data.shipment_status = "IN_TRANSIT" | В этом примере один контейнер находится в пути, поэтому статус — IN_TRANSIT. Для результата с несколькими контейнерами не присваивайте всем статус одного из них. |
attributes.ref_numbers = ["Order 123"] | note = "Order 123" | Перенесите Order 123 в note. Другие элементы ref_numbers сохраните отдельно. |
attributes.equipment_height = "high_cube" | tracked_item.data.data.containers[0].type = "40' High Cube Dry" | Размер, высота и тип указаны вместе в строке containers[].type. Отдельного equipment_height нет. |
События перевозки: код, дата и признак фактического события
Terminal49 — GET /containers/{id}/transport_events
Фрагмент: data.
[
{
"id": "77777777-7777-4777-8777-777777777777",
"type": "transport_event",
"attributes": {
"event": "container.transport.vessel_loaded",
"timestamp": "2026-10-01T04:00:00Z",
"timezone": "Asia/Singapore",
"location_locode": "SGSIN",
"voyage_number": "126E"
}
},
{
"id": "88888888-8888-4888-8888-888888888888",
"type": "transport_event",
"attributes": {
"event": "container.transport.estimated.vessel_arrived",
"timestamp": "2026-10-12T06:00:00Z",
"timezone": "Europe/Amsterdam",
"location_locode": "NLRTM",
"voyage_number": "126E"
}
}
]Cargotime — GET /v2/shipments
Фрагмент: data.data[0].tracked_item.data.data.
{
"locations": [
{
"id": 0,
"name": "Singapore",
"country": "Singapore",
"lat": 1.25,
"lng": 103.75
},
{
"id": 1,
"name": "Rotterdam",
"country": "Netherlands",
"lat": 51.95,
"lng": 4.14
}
],
"containers": [
{
"number": "MSCU1234567",
"events": [
{
"location": 1,
"status": "Vessel arrival",
"status_code": "VAD",
"date": "2026-10-12T08:00:00",
"actual": false,
"voyage": "126E"
},
{
"location": 0,
"status": "Loaded",
"status_code": "CLL",
"date": "2026-10-01T12:00:00",
"actual": true,
"voyage": "126E"
}
]
}
]
}Как сопоставить
| Terminal49 | Cargotime | Что изменить |
|---|---|---|
[0].attributes.event = "container.transport.vessel_loaded" | containers[0].events[1].status_code = "CLL" | В этом примере погрузка в порту отправления соответствует CLL. Для события погрузки при перегрузке используйте CLT. |
[1].attributes.event = "container.transport.estimated.vessel_arrived" | containers[0].events[0].actual = false | Для прогнозного прибытия проверяйте actual=false. Код прибытия судна при этом остаётся VAD. |
[0].attributes.timestamp = "2026-10-01T04:00:00Z" | containers[0].events[1].date = "2026-10-01T12:00:00" | В примере 04:00 UTC равно 12:00 в часовом поясе Сингапура. При переносе дат используйте исходный timezone, а не удаляйте Z. |
[0].attributes.location_locode = "SGSIN" | locations[0].name = "Singapore" | По event.location найдите запись в locations. Для проверки исходного места используйте UN/LOCODE SGSIN. |
[0].attributes.voyage_number = "126E" | containers[0].events[1].voyage = "126E" | Получайте номер рейса из event.voyage вместо voyage_number. Значение 126E остаётся прежним. |
[0].id = "77777777-7777-4777-8777-777777777777" | Нет прямого аналога | События нового ответа не имеют такого ID. Сохраните исходный ID вместе с архивными данными, если на него ссылается ваша система. |
Что сохранить отдельно
Отдельно сохраните сведения о терминалах, последнем бесплатном дне вывоза, ограничениях выдачи, сборах и пользовательских полях. Для каждого контейнера по коносаменту или букингу храните три значения: ID контейнера Terminal49, новый ID отслеживания и номер контейнера. Это позволит сохранить ссылки на прежние записи.
Обновлено