Cargotime

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:

  1. Создайте ключ в личном кабинете Cargotime.
  2. Замените базовый адрес на https://tracking.cargotime.ru/v2. Например, полный адрес запроса отслеживания — https://tracking.cargotime.ru/v2/tracking.
  3. Передавайте новый ключ в параметре URL api_key каждого запроса, включая пакетные задачи и управление вебхуками. Ключи и токены прежнего сервиса не подходят.

Правила использования ключа и ограничения запросов — в разделе аутентификации.

Отслеживания и идентификаторы

Terminal49CargotimeЧто изменить
tracking_requestВременная задача пакетной обработкиИспользуйте задачу только для получения результата запуска. После её завершения сохраните постоянный ID отслеживания, а историю tracking_request выгрузите отдельно.
shipmentЗапись отслеживания и данные перевозкиДля каждого отслеживаемого номера сохраните новый ID. Контейнеры по коносаменту или букингу будут находиться внутри результата этой записи.
containercontainers[]Находите контейнер по containers[].number. Отдельного постоянного ID контейнера и методов управления им здесь нет.
transport_eventcontainers[].events[]Получайте события из массива выбранного контейнера. Обновите обработку кодов, фактических и плановых дат по таблицам ниже.

Соответствие операций

Terminal49CargotimeЧто изменить
POST /tracking_requestsPOST /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 /containersGET /v2/shipmentsПолучайте страницы отслеживаний. Контейнеры каждой записи находятся в tracked_item.data.data.containers[].
GET /shipments/{id}, GET /containers/{id}GET /v2/shipmentsНайдите запись по сохранённому новому ID в страницах списка. Если нужен конкретный контейнер, выберите его по номеру внутри записи.
GET /containers/{id}/transport_eventsGET /v2/shipments → containers[].events[]Получайте события выбранного контейнера из сохранённой записи. Отдельного метода со своей постраничной выдачей событий нет.
PATCH /tracking_requests/{id}PATCH /v2/shipments/{id} (частично)Перенесите ref_number в note, если он укладывается в 40 символов. Изменить номер перевозчика или SCAC через этот метод нельзя.
GET /shipping_linesGET /v2/companiesНайдите перевозчика по SCAC и проверьте поддержку нужного типа номера в cn, bl, bk.
PATCH /shipments/{id}/stop_tracking, PATCH /shipments/{id}/resume_trackingDELETE /v2/shipments / новый запускДля остановки передайте новые ID в shipmentIds. Повторную активацию выполняйте запросом отслеживания с учётом жизненного цикла.
/webhooks, /webhook_notifications/v2/webhooks, /v2/webhook-notificationsСоздайте вебхуки заново и обновите проверку подписи и разбор уведомлений. Журнал доставок доступен через /v2/webhook-notifications.

Параметры запроса

Terminal49CargotimeЧто изменить
data.attributes.request_numbertracked_items[].track_number.valueПередайте request_number в tracked_items[].track_number.value. Уберите оболочку JSON:API data.attributes.
data.attributes.request_typetracked_items[].track_number.typeОставьте container без изменения, замените bill_of_lading на bl, booking_number на bk.
data.attributes.scactracked_items[].companyПроверьте SCAC через GET /v2/companies и передайте его в tracked_items[].company.
auto_detect_vocc_scaccompany=AUTO (частично)Для автоматического определения перевозчика передайте company: "AUTO" только с типом container. Для коносамента и букинга укажите SCAC.
POST: ref_numbers[] / initial_custom_fields, PATCH: ref_numbernote + ваша системаПосле получения ID сохраните одну подпись до 40 символов в note. Массив номеров и произвольные поля сохраните в своей базе.
include / filter / pagepage / 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.

Terminal49CargotimeКак обработать ответ
data.id у tracking_requestdata.task_id (частично)Не используйте task_id как постоянный ID. Получите результат задачи и сохраните data.results[].data.tracking_metadata.id.
attributes.status: pending / created / faileddata.status + results[].success / statusПроверяйте data.status задачи, затем success и status каждого результата. PROCESSED означает завершение обработки, но не успех всех номеров.
relationships.tracked_object.dataresults[].data.tracking_metadata.idСохраните связь исходного tracked_object с новым постоянным ID. Новый ответ не содержит объекта JSON:API relationships.
container.attributes.numbertracked_item.data.data.containers[].numberПолучайте номер из containers[].number. При нескольких контейнерах выбирайте нужный элемент по номеру.
transport_event.attributes.eventcontainers[].events[].status_code / actualОбрабатывайте status_code и actual раздельно. Например, погрузка в порту отправления — CLL, при перегрузке — CLT.
transport_event.attributes.timestamp / timezone / voyage_numbercontainers[].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"
    }
}

Как сопоставить

Terminal49CargotimeЧто изменить
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 и используйте его для поиска записи в списке и изменения подписи.

Контейнер, связь с перевозкой и тип оборудования

Как сопоставить

Terminal49CargotimeЧто изменить
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 нет.

События перевозки: код, дата и признак фактического события

Как сопоставить

Terminal49CargotimeЧто изменить
[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 отслеживания и номер контейнера. Это позволит сохранить ссылки на прежние записи.

Обновлено