Developer migration guide

SeaRates to Vizion Container Tracking API

Register a container, B/L, or booking once as a reference. Vizion then delivers the same update payload two ways: pushed to your callback_url as updates are created, or pulled from GET /references/{referenceId}/updates.

Your existing polling workflow can stay largely as-is: keep your scheduler and poll the updates endpoint on your own cadence. Webhooks are recommended, not required. This guide maps the fields, parameters, and errors you use today onto their Vizion equivalents.

Quick links
Overview

Architectural shift

In SeaRates every request is a fresh lookup, and you own the schedule, the cache, and the deduplication. In Vizion you create a reference once and Vizion keeps it updated. Read those updates by push to a callback URL or by pull from the updates endpoint. Both return the same payload, so every mapping below applies either way.

Before · SeaRates
cron every 4h
→ GET /tracking
→ diff against your cache
→ dedupe events
→ write to your DB

Every call spends quota. Freshness is capped by the polling interval.

To keep this shape, point the same scheduler at GET /references/{id}/updates.

After · Vizion
POST /references (once)
→ Vizion polls the carrier
→ POST to your callback_url
   or GET /updates when you ask
→ write to your DB

No cache layer or dedup logic either way. Push removes the polling loop. Pull keeps it on your cadence.

At a glance

Quick comparison

Platform comparison
Aspect SeaRates Vizion
Tracking model Poll on demand Subscribe once, then push or poll
Data delivery Synchronous GET response Webhook POST, or pull via GET. Same payload.
Authentication API key as query parameter (?api_key=) API key as header (X-API-Key)
Base URL https://tracking.searates.com https://prod.vizionapi.com
Batch tracking Not supported. One request per container. Not needed. Subscriptions run continuously.
Webhook support None Optional. HMAC-signed delivery.
Rate limit 100 requests / 20 seconds Demo: 50 active references at a time, 15,000 API requests per monthly cycle. Production: no rate limits unless otherwise agreed. Demo environment limits →
Carrier coverage 239 shipping lines by SCAC 61 supported carriers, ~98% of global volume. 29 have a dedicated carrier_code value.
Carrier ID format SCAC code, e.g. CMDU carrier_code enum, e.g. CMDU
Reference types Container, B/L, booking per request Container, B/L, booking per subscription
Auto carrier detection sealine=auto parameter Omit carrier_code and ACI resolves it
Event classification Free text + SMDG event codes Free text; DCSA journey events available as an account add-on
AIS vessel position Inline with tracking (route=true&ais=true) Separate endpoint: GET /references/{id}/trace Container trace documentation →
ETA route.pod.predictive_eta in response In the standard update payload: milestones with source "Vizion" and journey_event.event_classifier "EST". estimated_event_alerts webhook events are supplemental, not the only source.
Shipment status metadata.status enum Reference status covers tracking state; shipment progress is read from milestones Reference status documentation →
STEP 01

Authentication

The API key moves from a query parameter to the X-API-Key request header. SeaRates keys do not carry over. Contact Vizion sales for a key.

SeaRates
curl -X GET "https://tracking.searates.com/tracking\
?api_key=YOUR_SEARATES_KEY\
&number=MRKU9465770\
&sealine=MAEU\
&type=CT"
Vizion
curl -X POST https://prod.vizionapi.com/references \
  -H "X-API-Key: YOUR_VIZION_KEY" \
  -H "Content-Type: application/json" \
  -d '{"container_id": "MRKU9465770",
       "carrier_code": "MAEU"}'
STEP 02

Reference lifecycle

Replace per-request lookups with a reference lifecycle. Vizion decides when to check each data source and makes every new update available by push and by pull.

Update cadence · Smart Updates

Smart Updates is enabled by default. It adjusts how often each data source is checked based on shipment status. Terminal and rail sources are checked more often than a vessel mid-ocean, which reduces latency around arrival, discharge, and transshipment.

With Smart Updates off, checks fall back to a flat configured interval. Default is 12 hours. Intervals of 6, 3, or 2 hours are available on request.

Smart Updates documentation →
01

Create a reference

One call per container, B/L, or booking. Store the returned reference_id for lookups.

POST /references
{
  "container_id": "MRKU9465770",
  "carrier_code": "MAEU",
  "callback_url": "https://your-server.com/vizion-webhook"
}
02

Read updates

Use either mechanism, or both. The payload is identical.

A · Automatic notification

A listener on your callback_url receives each update as soon as it is created. No request from you.

POST https://your-server.com/vizion-webhook
B · Pull on demand

Poll on your own cadence, or request by reference ID, for the most recent update.

GET /references/{referenceId}/updates
03

Deactivation is automatic

Vizion auto-unsubscribes references, so no teardown call is required. Deactivation does not always mean delivery — check reference.deactivate_reason. Deactivate manually only to stop tracking early.

shipment_completed The journey finished. Safe to mark delivered.
too_long_without_updates Tracking stopped without completing. Flag for review — do not mark delivered.
exceeded_extraction_attempt_threshold Tracking stopped without completing. Flag for review — do not mark delivered.
DELETE /references/{referenceId}
STEP 03

Request parameter mapping

One SeaRates poll request becomes one reference creation.

Creating a reference
SeaRates parameter Vizion equivalent Notes
number container_id / bill_of_lading / booking_number SeaRates combines these in one param. Vizion uses typed fields.
type=CT container_id Track by container →
type=BL bill_of_lading Track by B/L →
type=BK booking_number Track by booking →
sealine carrier_code Same SCAC values for most carriers
sealine=auto (omit carrier_code) Vizion uses Automatic Carrier Identification, limited to its 29-carrier network and excluding RCLU
force_update No equivalent Vizion controls refresh cadence
route Always included Port data is always returned in updates
ais GET /references/{id}/trace AIS is a pull endpoint, not part of milestone updates
api_key X-API-Key header Query parameter becomes a header
Combined number format

SeaRates accepts a combined value in one number field: BL_NUMBER/CONTAINER_NUMBER, and BOOKING_NUMBER/CONTAINER_NUMBER for bookings. Vizion takes one typed field per reference type.

Track by B/L using bill_of_lading, or by booking using booking_number. In both cases Vizion identifies every container on the document and creates a child reference for each.

If you tracked linked shipments in SeaRates, note that Vizion models the relationship on the child: each child reference carries parent_reference_id. There is no child_reference_ids array on the parent. Associate children to parents using the field on the child.

STEP 04

Response data mapping

SeaRates stores locations, vessels, and facilities in top-level arrays referenced by integer ID. Vizion inlines full objects on each milestone. Your ID-resolution code can be deleted.

Envelope
SeaRates Vizion Notes
status: "success" HTTP 200 SeaRates puts status in the body. Vizion uses standard HTTP codes.
message: "OK" No equivalent
data: { ... } Webhook body, or GET /updates response
Shipment-level fields
SeaRates field Vizion equivalent Notes
metadata.status Reference status Check the reference status for tracking state, and reference.deactivate_reason for why tracking stopped. Shipment progress itself comes from milestones. Reference status documentation →
metadata.sealine payload.carrier_scac Same SCAC codes
metadata.number payload.container_id / bill_of_lading / booking_number Split into typed fields
metadata.api_calls, unique_shipments No equivalent Not exposed per response
metadata.from_cache, updated_at, cache_expires No equivalent Caching is internal to Vizion
Container fields
SeaRates field Vizion equivalent Notes
containers[].number payload.container_id One container per reference
containers[].iso_code — "45G1" payload.container_iso — "45G1", or "40' HIGH CUBE" Vizion returns the ISO 6346 code when it can be mapped at payload-creation time, and a descriptive text string otherwise. Handle both shapes.
containers[].size_type payload.container_iso Same field. When container_iso falls back to descriptive text, that text is closest to SeaRates' size_type.
containers[].status No direct equivalent Inferred from milestones
containers[].events[] payload.milestones[] See milestone mapping
containers[].events_mirrored No equivalent
Milestone / event mapping
SeaRates event field Vizion milestone field Transformation
date — "YYYY-MM-DD HH:MM:SS" timestamp Parse and convert to ISO 8601
actual (boolean) planned (boolean) Inverted: planned = !actual
description description Carrier text is replaced by a Vizion standardized description
description raw_description Original carrier text, kept verbatim
vessel → vessels[].name vessel Vizion inlines the name
vessel → vessels[].imo vessel_imo Vizion surfaces the IMO as a top-level attribute.
vessel → vessels[].mmsi vessel_mmsi Vizion inlines the MMSI
voyage voyage Direct pass-through. The only identical field name on both APIs.
transport_type — VESSEL, TRUCK, RAIL mode — Vessel, Truck, Rail Same values, different casing
event_type — EQUIPMENT, TRANSPORT journey_event.journey_type DCSA journey events are opt-in. Contact Vizion to enable.
event_code — ARRI, DEPA, LOAD, DISC journey_event.event_type Same DCSA-derived codes, different structure
status (3-char code) No direct equivalent
type — sea, land No direct equivalent
order_id No equivalent Milestones are ordered by array position
facility → facilities[].name location.facility Facility moves onto the location object
is_date_from_sealine No equivalent
is_additional_event No equivalent
(none) source — carrier, terminal, ais, rail Where the milestone came from Data sources documentation →
(none) shipment_location — PRE, POL, POD, PDE, RTP DCSA addon classifying where in the journey the event occurred. [CONFIRM WITH ENG] whether this requires contacting support to enable, as journey_type does. DCSA event code types →
Location mapping
SeaRates location field Vizion location field Notes
name name Direct match
state state Direct match
country country Both use full country names
country_code No equivalent Full country name only
locode unlocode Same data, renamed field
lat geolocation.latitude Flat field becomes nested
lng geolocation.longitude Flat field, renamed and nested
timezone No equivalent Not included in responses
(none) city Dedicated city field. Requires Enhanced Location Reporting.
(none) facility Populated from facility data. Requires Enhanced Location Reporting.
(none) smdg_cd, bic_cd, splc_cd, firms_cd Facility identification codes. Requires Enhanced Location Reporting. Enhanced locations documentation →
Port / route mapping
SeaRates route Vizion payload field Meaning
route.prepol inland_origin Place of receipt / inland origin
route.pol origin_port Port of loading
route.pod destination_port Port of discharge
route.postpod inland_destination Final destination / inland delivery point
route[].date, route[].actual No equivalent Port event dates and actuality come through milestones, not port fields
Vessel mapping
SeaRates vessel field Vizion milestone field Notes
vessels[].name vessel Name string
vessels[].imo vessel_imo IMO number, surfaced as a top-level attribute
vessels[].mmsi vessel_mmsi MMSI number
vessels[].call_sign No equivalent
vessels[].flag No equivalent
Inverted flag and timestamp format

SeaRates actual is inverted in Vizion: planned = !actual. Timestamps change from YYYY-MM-DD HH:MM:SS to ISO 8601 with offset.

STEP 05

Event description mapping

SeaRates event.description values are free text and vary by carrier. Vizion maps them to a standardized set of roughly 130 descriptions and keeps the carrier's original string in raw_description. SeaRates strings are case-insensitive, and new ones appear over time.

The milestone lists live in the API docs. Core milestones are the eight Vizion makes an effort to provide for every reference. Standardized milestones are the full set your SeaRates descriptions resolve into.

Unmapped descriptions

Anything Vizion cannot map passes through as raw text in both description and raw_description. Some Vizion milestones have no SeaRates equivalent, including barge and feeder events and transshipment variants, because they come from direct carrier integrations.

STEP 06

Carrier code mapping

Both APIs identify carriers by SCAC, and most codes are identical. Vizion supports 61 carriers in total; 29 of those have a dedicated carrier_code value.

Automatic Carrier Identification

Omitting carrier_code lets ACI resolve the carrier, but only within its supported network of 29 carriers. RCLU is explicitly excluded.

If your SeaRates traffic includes carriers outside that network, do not rely on ACI. Pass the carrier SCAC on the reference directly. Check your carrier mix against the ACI list before cutover.

ACI and reference creation reference →
carrier_code enum · 29 of 61 supported carriers
ALPJ ANNU APLU CMDU COSU EGLV HASL HDMU HLCU KMTU MAEU MATS MSCU NSRU ONEY OOCL PCIU RCLU SAFM SEAU SMLM SNKO SUDU TMGB WECU WHLC WWSU YMLU ZIMU
Carriers sharing one code
Vizion carrier_code Covers
CMDU CMA CGM, APL, CNC, Containerships, MacAndrews, OPDR
MAEU Maersk, MCC Transport, Seago Line
ONEY ONE — K-Line, MOL, and NYK merged
HLCU Hapag-Lloyd, CSAV, Nile Dutch, UASC
SUDU Hamburg-Süd, CCNI
STEP 07

Handling webhooks

Optional. SeaRates has no webhooks. Vizion can POST updates to an HTTPS endpoint you expose. Skip this section if you are staying on the polling path. Use callback_url to receive everything, or the webhooks array to subscribe to specific events and sources.

Option A · callback_url
POST /references
{
  "container_id": "MRKU9465770",
  "carrier_code": "MAEU",
  "callback_url": "https://your-server.com/vizion-webhook"
}
Option B · webhooks array
POST /references
{
  "container_id": "MRKU9465770",
  "carrier_code": "MAEU",
  "webhooks": [
    {
      "callback_url": "https://your-server.com/vizion-webhook",
      "events": ["reference_update", "estimated_event_alerts"],
      "sources": ["carrier", "terminal"]
    }
  ]
}

Payload structure

{
  "id": "update-uuid",
  "status": "data_received",
  "reference_id": "ref-uuid",
  "organization_id": "org-uuid",
  "created_at": "2026-08-11T14:30:00.000Z",
  "payload": {
    "container_id": "MRKU9465770",
    "carrier_scac": "MAEU",
    "container_iso": "40' HIGH CUBE",
    "origin_port": { "name": "Shanghai", "country": "China", "unlocode": "CNSHA", ... },
    "destination_port": { "name": "Los Angeles", "country": "United States", "unlocode": "USLAX", ... },
    "milestones": [
      {
        "timestamp": "2026-08-10T08:14:00.000+08:00",
        "description": "Loaded on vessel",
        "raw_description": "Loaded to Vessel",
        "vessel": "MAERSK SELETAR",
        "vessel_imo": "9778791",
        "voyage": "234W",
        "planned": false,
        "mode": "Vessel",
        "source": "carrier",
        "location": {
          "name": "Shanghai",
          "country": "China",
          "unlocode": "CNSHA",
          "geolocation": { "latitude": 31.2304, "longitude": 121.4737 }
        }
      }
    ]
  }
}
Security

Payloads are signed with HMAC SHA-256. Verify the x-vizion-signature and digest headers. See webhook security.

Whitelist IP 54.164.144.86
Test before you go live
POST /webhooks/trigger/test
{ "callback_url": "https://your-server.com/vizion-webhook" }

Returns SUCCESS, REJECTED, or REQUEST_ERROR with full request and response detail.

STEP 08

Vizion-only features

Features with no SeaRates equivalent.

New in Vizion
Feature What it gives you
Webhook delivery Optional push delivery. Removes the polling loop if you want it gone.
HMAC verification Cryptographic payload verification on every delivery
Milestone source attribution Each milestone tagged source: carrier, terminal, ais, or rail
DCSA journey events Structured equipment, shipment, and transport events with event_classifier (ACT/PLN/EST), facility_type, and empty_indicator. Opt-in, no extra cost.
Raw and standardized descriptions raw_description and description on every milestone
AIS position trace GET /references/{referenceId}/trace returns vessel position history, plus a projected trace of the forward path
ETA change alerts estimated_event_alerts webhook events carry day and percent delta
Reference lifecycle events GET /references/{referenceId}/events returns an audit trail of extractions, status changes, activations, and deactivations
Last known positions GET /references/last-known-positions for a batch current-position query
Tags Up to 10 custom tags per reference for your internal metadata
B/L fan-out Track by B/L or booking; Vizion creates a child reference per container, each carrying parent_reference_id
Demurrage & detention charges charges data on the update payload (opt-in)
Cargo data Weight, quantity, seal numbers, volume, VGM measurements (opt-in)
Facility codes smdg_cd, bic_cd, splc_cd, and firms_cd on location objects. Requires Enhanced Location Reporting.
Enhanced Location Reporting

Facility codes and the richer location fields — city, facility, smdg_cd, bic_cd, splc_cd, and firms_cd — require Enhanced Location Reporting to be enabled on your account. Contact Vizion to enable it.

Enhanced locations documentation →
STEP 09

Behavior differences

SeaRates features that work differently, or that Vizion handles internally instead of exposing.

Differences to plan for
SeaRates feature Vizion equivalent
Shipment status enum Reference status reports tracking state, not shipment progress. Read progress from milestones, and check reference.deactivate_reason == "shipment_completed" for delivered shipments.
Geographic route paths Available as a projected trace: the vessel's forward path in addition to AIS position history.
Current position pin GET /references/last-known-positions, or the AIS trace endpoint
Inline AIS data Separate endpoint: GET /references/{id}/trace
Predictive ETA In the standard update payload — milestones with source "Vizion" and journey_event.event_classifier "EST". The estimated_event_alerts webhook events are supplemental, not the only source.
Cache metadata Not exposed. Vizion manages refresh internally.
Quota counters Not exposed per response
Per-event structured codes Available via opt-in DCSA journey events, with different structure
Force update Not available. Vizion controls refresh cadence.
Historical snapshots GET /references/{id}/updates returns all update history
Carrier list (239 carriers) GET /carriers returns 61 supported carriers. 29 of those have a dedicated carrier_code value in the ACI network.
Location timezone Not included in the API response
Location country_code Not included. Full country name only.
Vessel call_sign and flag Not included on milestones
STEP 10

Error handling

SeaRates returns HTTP 200 for both success and failure and puts the error in the envelope. Vizion uses standard HTTP status codes. Replace checks on response.status == "error" and message-string matching with status-code checks.

Vizion HTTP status codes
Code Meaning
400 Bad request. Malformed or missing parameter.
401 Unauthorized. API key lacks permissions.
403 Forbidden. No valid API key.
404 Not found. Reference does not exist.
422 Unprocessable entity. Valid syntax, rejected content (e.g. invalid container format).
429 Too many requests
500, 502, 503, 504 Server errors. Something went wrong on Vizion's end. These are rare.
Status code reference →
SeaRates error → Vizion equivalent
SeaRates error message Vizion equivalent
API_KEY_WRONG / API_KEY_ACCESS_DENIED / API_KEY_EXPIRED HTTP 401 or 403
API_KEY_LIMIT_REACHED / API_KEY_RATE_LIMIT HTTP 429
WRONG_PARAMETERS / WRONG_NUMBER / WRONG_TYPE HTTP 400
SEALINE_NOT_SUPPORTED HTTP 422, or auto_carrier_not_found on the reference
SEALINE_HASNT_PROVIDE_INFO / NO_CONTAINERS / NO_EVENTS last_update_status on the reference: no_data or extraction_failed
SEALINE_TEMPORARY_DISABLED / SEALINE_UNDER_MAINTENANCE / SEALINE_NO_RESPONSE Not surfaced. Vizion retries internally.
WRONG_SEALINE HTTP 422, invalid carrier_code
AUTO_CANT_DETECT_SEALINE last_update_status: "auto_carrier_not_found"
Ship it

Migration checklist

Every migration does the base path. Then pick one branch. The polling path is shorter because there is no endpoint for Vizion to call.

Base path · everyone
01
Get a Vizion API key
SeaRates keys do not carry over. Contact Vizion sales.
02
Switch authentication
Move the key from a query parameter to the X-API-Key header.
03
Create references
One POST /references per container, B/L, or booking, replacing the per-request lookup.
04
Map carrier codes
Verify your sealine values exist in the carrier_code enum. ACI covers only its 29-carrier network and excludes RCLU, so set the SCAC explicitly for anything outside it.
05
Handle B/L fan-out
Update any parent/child shipment logic to read parent_reference_id from child references. There is no child list on the parent.
06
Update response parsing
Inline objects instead of ID-referenced arrays, planned instead of actual, ISO 8601 timestamps. Same work on both paths.
07
Update error handling
Replace envelope-based error checks with HTTP status code checks.
08
Retire your cache and dedup layer
If you consume updates via webhook, keep a lightweight dedupe layer keyed on update ID. If you poll on demand, you're pulling current state — no dedupe needed.
09
Skip teardown, but read deactivate_reason
References auto-unsubscribe. Treat shipment_completed as delivered; flag too_long_without_updates and exceeded_extraction_attempt_threshold for review. Use DELETE /references/{id} only to stop tracking early.
Then pick one
Webhook path
Updates arrive as they are created
4 steps
W1
Set up a webhook endpoint
Expose an HTTPS endpoint that accepts Vizion POST payloads and pass it as callback_url.
W2
Implement signature verification
Validate the x-vizion-signature and digest headers.
W3
Whitelist the Vizion IP
Allow 54.164.144.86 if your firewall restricts inbound traffic.
W4
Test delivery before going live
POST /webhooks/trigger/test and confirm you get SUCCESS.
Polling path
Keep your existing SeaRates scheduler
2 steps
P1
Repoint your scheduler
Swap GET /tracking for GET /references/{id}/updates. Keep your existing cadence.
P2
Store the reference IDs
Persist reference_id from the creation response. It is the polling key.
Skipped on this path: endpoint setup, signature verification, IP whitelisting, and delivery testing.