Webhook
Shipment Webhook Event Subscription
Shipment Webhook event subscription is a service that delivers updated data in real time to subscribed endpoints when shipment data changes.
When a subscribed event occurs, the JSON payload is delivered to the registered endpoint via the request body.
The detailed structure of the JSON payload is as follows.
Events Object
{
"event_id": "31b1a972-677b-422c-a696-4228e3b5a8ff",
"event_occurred_at": "2025-12-01T04:22:15.805606262",
"event_name": "SHIPMENT.BL.UPDATED",
"payload": {}
}
| Fields | Type | Description |
|---|---|---|
| event_id | String | Unique identifier that identifies the event |
| event_occurred_at | String | Time when the event occurred yyyy-MM-dd'T'HH:mm:ss.SSSSSS |
| event_name | String | Name of the event that occurred |
| payload | Object | The payload value corresponding to the occurred event is delivered. |
SHIPMENT.BL.UPDATED PAYLOAD
{
"cargo_track_id": "3d8b1e76-8721-4e27-a98d-2bfb8193d4ee",
"line_cd": "HMM",
"bl_no": "HDMUPUSM12345678",
"cust_order_id": "REFERENCE_NO",
"cust_corp_name": null,
"cust_name": null,
"remark": null,
"is_active": true,
"registered_datetime": "2025-12-01T04:22:06.6305903Z",
"tracking_status": "TRACKING",
"is_container_plus": true,
"trade_type": "EXPRT",
"trans_type": "DIRECT",
"pol": {
"pol_name": "New Busan",
"pol_code": "KRBNP",
"init_etd": "2025-12-06T00:00:00+09:00",
"etd": "2025-12-06T00:00:00+09:00",
"atd": null,
"tx_atd": "2025-12-06T00:00:00+09:00"
},
"pod": {
"pod_name": "Manzanillo",
"pod_code": "MXZLO",
"init_eta": "2025-12-19T18:00:00-06:00",
"eta": "2025-12-19T18:00:00-06:00",
"ata": null,
"tx_ata": null
},
"current_vessel": {
"imo": "9976707",
"mmsi": "563262300",
"vessel_name": "ONE SAPPHIRE",
"voyage": "2547E"
},
"routes": [
{
"order": 1,
"pol_name": "New Busan",
"pol_code": "KRBNP",
"pod_name": "Manzanillo",
"pod_code": "MXZLO",
"imo": "9976707",
"mmsi": "563262300",
"vessel_name": "ONE SAPPHIRE",
"voyage": "2547E",
"init_etd": "2025-12-06T00:00:00+09:00",
"etd": "2025-12-06T00:00:00+09:00",
"atd": null,
"tx_atd": "2025-12-06T00:00:00+09:00",
"init_eta": "2025-12-19T18:00:00-06:00",
"eta": "2025-12-19T18:00:00-06:00",
"ata": null,
"tx_ata": null
}
],
"containers": [
{
"cntr_no": "CAIU7471046",
"cntr_sz": "40",
"cntr_tp": "DC",
"container_events": [
{
"port_code": "KRPUS",
"event_type": "LOADING_ON_VESSEL",
"transportation": "VESSEL",
"is_actual": true,
"event_datetime": "2025-12-05T16:45:00+09:00"
},
{
"port_code": "KRPUS",
"event_type": "VESSEL_DEPARTURE_FROM_PORT",
"transportation": "VESSEL",
"is_actual": true,
"event_datetime": "2025-12-06T00:00:00+09:00"
},
{
"port_code": "MXZLO",
"event_type": "VESSEL_ARRIVAL_AT_PORT",
"transportation": "VESSEL",
"isActual": false,
"event_datetime": "2025-12-19T17:00:00-06:00"
},
{
"port_code": "MXZLO",
"event_type": "VESSEL_BERTHING_ON_PORT",
"transportation": "VESSEL",
"isActual": false,
"event_datetime": "2025-12-19T18:00:00-06:00"
},
{
"port_code": "MXZLO",
"event_type": "DISCHARGING_FROM_VESSEL",
"transportation": "VESSEL",
"isActual": false,
"event_datetime": "2025-12-20T11:02:24-06:00"
}
]
}
]
}
Payload
| Field | Type | Description |
|---|---|---|
| cargo_track_id | String | Cargo Tracking ID |
| line_cd | String | Carrier code |
| bl_no | String | B/L number |
| cust_order_id | String | Customer order ID (Reference/Order ID) |
| cust_corp_name | String | null | Customer company name |
| cust_name | String | null | Customer name |
| remark | String | null | Remark |
| is_active | Boolean | Whether tracking is active |
| registered_datetime | String | Registered datetime (ISO-8601, e.g. yyyy-MM-dd'T'HH:mm:ssZ) |
| tracking_status | String | Tracking status (e.g. INIT, PENDING, TRACKING, COMPLETE, etc.) |
| is_container_plus | Boolean | Whether Container Plus is enabled |
| trade_type | String | Trade type (EXPRT/IMPRT) |
| trans_type | String | Transportation type (e.g. DIRECT, TS, etc.) |
| pol | Object | POL (Port of Loading) object |
| pod | Object | POD (Port of Discharge) object |
| current_vessel | Object | Current vessel object |
| routes | Array<Object> | Route/leg list |
| containers | Array<Object> | Container list |
Tracking Status
| Code | Description |
|---|---|
| INIT | Waiting |
| PENDING | Retrying |
| EXPIRED | Retry failed for 7 days |
| BL_INVALID | Invalid BL input |
| TRACKING | Tracking |
| COMPLETE | Completed |
| UNPAID | Insufficient credits |
POL Information
| Field | Type | Description |
|---|---|---|
| pol.pol_name | String | Port of loading name |
| pol.pol_code | String | Port of loading code |
| pol.init_etd | String | null | Initially collected ETD yyyy-MM-dd'T'HH:mm:ssXXX |
| pol.etd | String | null | ETD yyyy-MM-dd'T'HH:mm:ssXXX |
| pol.atd | String | null | ATD yyyy-MM-dd'T'HH:mm:ssXXX |
| pol.tx_atd | String | null | ATD provided by TRADLINX yyyy-MM-dd'T'HH:mm:ssXXX |
POD Information
| Field | Type | Description |
|---|---|---|
| pod.pod_name | String | Port of discharge name |
| pod.pod_code | String | Port of discharge code |
| pod.init_eta | String | null | Initially collected ETA yyyy-MM-dd'T'HH:mm:ssXXX |
| pod.eta | String | null | ETA yyyy-MM-dd'T'HH:mm:ssXXX |
| pod.ata | String | null | ATA yyyy-MM-dd'T'HH:mm:ssXXX |
| pod.tx_ata | String | null | ATA provided by TRADLINX yyyy-MM-dd'T'HH:mm:ssXXX |
Current Vessel Information
| Field | Type | Description |
|---|---|---|
| current_vessel.imo | String | IMO number |
| current_vessel.mmsi | String | MMSI number |
| current_vessel.vessel_name | String | Vessel name |
| current_vessel.voyage | String | Voyage |
routes[*]
| Field | Type | Description |
|---|---|---|
| routes[].order | Number | Leg order |
| routes[].pol_name | String | Port of loading name |
| routes[].pol_code | String | Port of loading code |
| routes[].pod_name | String | Port of discharge name |
| routes[].pod_code | String | Port of discharge code |
| routes[].imo | String | IMO number |
| routes[].mmsi | String | MMSI number |
| routes[].vessel_name | String | Vessel name |
| routes[].voyage | String | Voyage |
| routes[].init_etd | String | Initially collected ETD yyyy-MM-dd'T'HH:mm:ssXXX |
| routes[].etd | String | null | ETD yyyy-MM-dd'T'HH:mm:ssXXX |
| routes[].atd | String | null | ATD yyyy-MM-dd'T'HH:mm:ssXXX |
| routes[].tx_atd | String | null | ATD provided by TRADLINX yyyy-MM-dyyyy-MM-dd'T'HH:mm:ssXXX |
| routes[].init_eta | String | null | Initially collected ETA yyyy-MM-dd'T'HH:mm:ssXXX |
| routes[].eta | String | null | ETA yyyy-MM-dd'T'HH:mm:ssXXX |
| routes[].ata | String | null | ATA yyyy-MM-dd'T'HH:mm:ssXXX |
| routes[].tx_ata | String | null | ATA provided by TRADLINX yyyy-MM-dyyyy-MM-dd'T'HH:mm:ssXXX |
containers[*]
| Field | Type | Description |
|---|---|---|
| containers[].cntr_no | String | Container number |
| containers[].cntr_sz | String | Size |
| containers[].cntr_tp | String | Type |
| containers[].seal_no | String | Seal number |
| containers[].container_events | Array | Container event list |
containers[].containerEvents[*]
| Field | Type | Description |
|---|---|---|
| containers[].container_events[].port_code | String | Port code |
| containers[].container_events[].event_type | String | Event type |
| containers[].container_events[].transportation | String | Transportation mode |
| containers[].container_events[].is_actual | Boolean | Whether actual |
| containers[].container_events[].event_datetime | String | Event datetime yyyy-MM-dd'T'HH:mm:ssXXX |
Container Event Types
| Code | Description |
|---|---|
| CONTAINER_PICK_UP | Container pickup |
| LOADING_ON_VESSEL | Loading on vessel |
| VESSEL_DEPARTURE_FROM_PORT | Vessel departure from port |
| VESSEL_ARRIVAL_AT_PORT | Vessel arrival at port |
| VESSEL_BERTHING_ON_PORT | Vessel berthing at port |
| DISCHARGING_FROM_VESSEL | Discharging from vessel |
| GATE_IN | Gate in to terminal or container yard |
| GATE_OUT | Gate out from terminal or container yard |
| RAIL_LOADING | Rail loading |
| RAIL_DEPARTURE | Rail departure |
| RAIL_ARRIVAL | Rail arrival |
| RAIL_UNLOADING | Rail unloading |
| PICKING_UP_BY_CONSIGNEE | Cargo is being picked up by the consignee to take delivery |
| DELIVERING_TO_CONSIGNEE | Cargo is being delivered to the consignee |
| EMPTY_CONTAINER_RETURN | Empty container return |
Transportation Mode Types
| Code | Description |
|---|---|
| VESSEL | Vessel |
| FEEDER | Feeder vessel (small container vessel) |
| BARGE | Barge (non- or low-powered cargo vessel) |
| RAIL | Rail (train) |
| TRUCK | Truck |
Getting Started
To receive webhook events, you must be operating a server that can receive webhook events.
Register and test your endpoint by following the steps below.
1. Create a Webhook Endpoint Function
TRADLINX Webhook is delivered as a JSON payload.
Therefore, you must implement an HTTPS endpoint that can handle webhook requests.
Endpoint Configuration Guide
- The endpoint host supports HTTPS protocol only.
- Implement an endpoint that allows the event you want to subscribe to and the HTTP method (GET, POST, etc.) supported by that event.
- The request body is a JSON payload.
- After receiving the payload, your endpoint must return an HTTP status of 2xx (200, 201, etc.) to be recorded as successfully received.
- Other statuses are not recorded as successful, and if failures repeat, the endpoint may be switched to an inactive state.
- Process the payload as quickly as possible.
- If the volume of webhook deliveries surges, the endpoint host may be overloaded.
- If the response waiting time exceeds 10 seconds and repeats 3 or more times, it may be switched to an inactive state.
- To prevent these issues, asynchronous processing is recommended.
Recommended logic that the endpoint should perform
- Parse the received JSON payload
- Extract key fields such as
event_id,event_name,event_occurred_at,payload.cargo_track_id, etc.event_idcan be used later to re-send failed events.
- Record receipt success/failure in a monitoring system
2. Register the Endpoint
-
Currently, webhook endpoints are managed directly by TRADLINX.
-
Please send the following information to tech.support@tradlinx.com.
- The currently supported event is SHIPMENT.BL.UPDATED, and requests are made only with HTTP METHOD: POST.
Submission Items
| Item | Description |
|---|---|
| Event name to register | SHIPMENT.BL.UPDATED |
| Webhook Endpoint URL | Publicly accessible HTTPS URL https://<your-website>/<your-webhook-endpoint> |
| Authorization | TRADLINX supports HTTP Basic Authentication by default. When registering your Webhook Endpoint, please provide a Username and Password. When sending webhooks, TRADLINX will include the Authorization header in the form Basic {credentials}, where {credentials} is the Base64-encoded value of the username:password string. If you require additional/custom headers beyond Basic Auth, prior coordination is required. |
3. Test
Once webhook endpoint registration is completed, a test mock event is automatically generated.
Using the API below, you can view the list of webhook events provided by TRADLINX or manually publish the mock event to the endpoint by re-sending it directly.
Use the mock event re-send feature to test whether your webhook endpoint works properly.
4. Handle Webhook Events (Update Tracking Data)
- To receive webhooks properly, you must register the shipments to be tracked via the API or SaaS (OceanVisibility).
- Webhooks are sent for shipments among registered tracking targets when a progress status change or shipment status change occurs.
- When receiving a webhook event, process the data by referring to the guide below.
Guide
- Store the
cargo_track_idreturned when registering a shipment. - The identifier of the shipment data contained in the event payload that is updated when an event occurs is the
cargo_track_idreturned at registration. - Save or update data based on
cargo_track_id.- If
cargo_track_iddoes not exist in storage, save it as a new shipment record. - If
cargo_track_idexists in storage, find newer data based onevent_occurred_atand update it.
- If
Retrieve Event List
- Various issues can occur in the process of delivering events to the webhook endpoint (network environment, DNS resolution issues, SSL issues, etc.).
- TRADLINX may also fail to deliver events properly due to other causes.
- The retention period for event data is limited to one month, after which the data will be deleted.
Retrieve Occurred Events
- Events can be checked via the Event List Retrieval API.
- In the list, you can check each event status (SUCCESS / FAILURE / DELIVERED / DNS_RESOLUTION_FAILURE).
- Retrieves the webhook delivery history (including success/failure) that occurred for the client account.
- The request requires authentication headers (tx-clientid, tx-apikey).
Request
GET /partners/track/webhook/events
Authentication Headers
| Header | Description |
|---|---|
| tx-clientid | Client ID issued for API integration |
| tx-apikey | API key for client authentication |
Query Parameters
| Field | Type | Description |
|---|---|---|
| *status | String | Event status to retrieve (SUCCESS_RESPONSE, FAILURE_RESPONSE, DELIVERED, FAILURE_UNKNOWN_HOST, FAILURE_REQUEST_TIMEOUT, FAILURE_CONNECTION_REFUSED) |
| *page | number | Page number (min: 1) |
| *size | number | Page size (range: 1~1000) |
curl -X GET "https://api.tradlinx.com/partners/track/webhook/events?page=[Page]&size=[Size]&status=[Status]" \
-H "tx-clientid: [Client ID]" \
-H "tx-apikey: [API Key]"
Response
{
"content": [
{
"id": "8f6c1c4b-0ae4-4f31-9df7-2a13d5e4bc11",
"event_name": "SHIPMENT.BL.UPDATED",
"status": "SUCCESS_RESPONSE",
"payload": "{\"sample\": \"payload\"}",
"payload_type": "REAL",
"payload_version": "v1",
"is_resendable": true,
"occurred_datetime": "2025-12-10T14:22:11",
"created_datetime": "2025-12-10T14:22:12"
},
{
"id": "4c2a7512-9b5c-4bd1-bd0a-afb22d8c1120",
"event_name": "SHIPMENT.BL.UPDATED",
"status": "SUCCESS_RESPONSE",
"payload": "{\"sample\": \"payload\"}",
"payload_type": "REAL",
"payload_version": "v1",
"is_resendable": false,
"occurred_datetime": "2025-12-10T14:20:02",
"created_datetime": "2025-12-10T14:20:03"
}
],
"pagination": {
"current_page": 1,
"has_next": false,
"total_page": 10,
"total_size": 10
}
}
Response
| Field | Type | Description | Remark |
|---|---|---|---|
| api_version | string | API version | v3 |
| content | Event | Events | |
| transaction_time | string | Time when the response was provided | yyyy-MM-dd'T'HH:mm:ss.SSSSSS |
| size | number | Size of content | |
| pagination | Pagination | Pagination info |
Pagination
| Field | Type | Description |
|---|---|---|
| total_size | number | Total data size |
| total_page | number | Maximum page number |
| current_page | number | Current page number |
| has_next | boolean | Whether there is a next page |
Event
| Fields | Type | Description |
|---|---|---|
| id | string | Unique Webhook event ID |
| event_name | string | Webhook event name |
| status | string | Webhook request result status |
| payload | string | Raw JSON payload sent in the actual webhook request |
| payload_type | string | Indicates whether the payload is test (Mock) data |
| payload_version | string | Payload version |
| is_resendable | boolean | Whether the event can be resent |
| occurred_datetime | string | Time when the event occurred yyyy-MM-dd'T'HH:mm:ss.SSSSSS |
| created_datetime | string | Time when it was stored as a log yyyy-MM-dd'T'HH:mm:ss.SSSSSS |
Status Code Details
| Code | Description |
|---|---|
SUCCESS_RESPONSE | The target server returned a successful (2xx) response to the webhook request |
FAILURE_RESPONSE | The target server did not return a successful (2xx) response to the webhook request |
DELIVERED | The event occurred at Tradlinx; status before sending the request to the endpoint |
FAILURE_UNKNOWN_HOST | The endpoint host could not be resolved via DNS |
FAILURE_REQUEST_TIMEOUT | The request to the endpoint timed out |
FAILURE_CONNECTION_REFUSED | The endpoint host refused the connection |
Payload Type Details
| Code | Description |
|---|---|
MOCK | Test payload |
REAL | Payload generated by a real event |
Retrieve the Event Detail
By looking up the details of a specific event, you can check the following information:
- HTTP status code of the delivery attempt
- Response body
- Response headers
- Attempt time
Using this information, you can quickly determine why the webhook endpoint failed to receive the event.
Retrieves all request attempt logs for a specific webhook event.
If an event is retried multiple times, all attempts are returned as an array.
Request
GET /partners/track/webhook/events/{event_id}/log
Path Variable
| Variable | Type | Description |
|---|---|---|
| event_id | string | Webhook Event ID to retrieve |
Authentication Headers
| Header | Description |
|---|---|
| tx-clientid | Client ID issued for API integration |
| tx-apikey | API key for client authentication |
curl -X GET "https://api.tradlinx.com/partners/track/webhook/events/[Event ID]/log" \
-H "tx-clientid: [Client ID]" \
-H "tx-apikey: [API Key]"
Response
{
"content": [
{
"id": 101,
"event_id": "8f6c1c4b-0ae4-4f31-9df7-2a13d5e4bc11",
"request_cause": "SUCCESS",
"request_method": "POST",
"request_url": "https://api.example.com/webhook",
"request_status": "SUCCESS",
"request_datetime": "2025-12-10T14:10:20.123456",
"response_http_status": 200,
"response_body": "{\"result\":\"ok\"}",
"response_header": "{\"Content-Type\":\"application/json\"}",
"response_datetime": "2025-12-10T14:10:20.543210",
"attempts": 1
},
{
"id": 102,
"event_id": "8f6c1c4b-0ae4-4f31-9df7-2a13d5e4bc11",
"request_cause": "SUCCESS",
"request_method": "POST",
"request_url": "https://api.example.com/webhook",
"request_status": "FAILED",
"request_datetime": "2025-12-10T14:12:05.333222",
"response_http_status": 504,
"response_body": "",
"response_header": "{\"Content-Type\":\"application/json\"}",
"response_datetime": "2025-12-10T14:12:10.888999",
"attempts": 2
}
],
"pagination": {
"current_page": 1,
"has_next": false,
"total_page": 10,
"total_size": 10
}
}
Response Body
| Field | Type | Description | Remark |
|---|---|---|---|
| api_version | string | API version | v3 |
| content | EventLog | Event logs | |
| transaction_time | string | Time when the response was provided | yyyy-MM-dd'T'HH:mm:ss.SSSSSS |
| size | number | Size of content | |
| pagination | Pagination | Pagination info |
Pagination
| Field | Type | Description |
|---|---|---|
| total_size | number | Total data size |
| total_page | number | Maximum page number |
| current_page | number | Current page number |
| has_next | boolean | Whether there is a next page |
Event Log
| Field | Type | Description |
|---|---|---|
| id | number | Unique attempt ID |
| event_id | string | Parent Webhook Event ID |
| request_cause | string | Reason/cause for the request |
| request_method | string | HTTP method (POST, etc.) |
| request_url | string | Request URL |
| request_status | string | Request status (SUCCESS / FAILED, etc.) |
| request_datetime | string | Time when the request was made yyyy-MM-dd'T'HH:mm:ss.SSSSSS |
| response_http_status | number | HTTP status code returned by the target server |
| response_body | string | Response body returned by the target server (raw string) |
| response_header | string | Response headers returned by the target server (raw JSON string) |
| response_datetime | string | Time when the response was completed yyyy-MM-dd'T'HH:mm:ss.SSSSSS |
| attempts | number | Total number of attempts for the event |
requestCause
| Value | Description |
|---|---|
| ON_EVENT | Normal case: the webhook request was triggered by an event occurrence |
| RETRY_ON_FAILURE_RESPONSE | Retry webhook request triggered due to a non-2xx response |
| RETRY_ON_FAILURE_REQUEST_TIMEOUT | Retry webhook request triggered due to a request timeout |
| ON_API | The event was triggered via API |
requestStatus
| Value | Description |
|---|---|
| PENDING | Request has been sent to the endpoint and is waiting for a response |
| SUCCESS | Request has been sent to the endpoint and a response was received |
| FAILURE_UNKNOWN_HOST | Request was made to a host that cannot be resolved via DNS |
| FAILURE_REQUEST_TIMEOUT | Request to the endpoint timed out |
| FAILURE_CONNECTION_REFUSED | The endpoint host refused the connection |
| UNKNOWN | Unknown failure |
Webhook Retry (Automatic + Manual)
If the webhook endpoint fails to receive an event, TRADLINX performs up to 3 automatic retries using an exponential backoff strategy after an initial 2-second delay.
If the event is still not received despite automatic retries, the user can check failed events via the Event List Retrieval API provided in the API documentation.
If you want to receive a specific event again, call the Webhook Event Resend API using the event_id obtained from the list to immediately receive that event again.
Webhook Event Resend
- Force re-send (retry) a specific webhook event.
- Retries are performed regardless of the event’s existing status (SUCCESS/FAILURE, etc.).
- The retention period for event data is limited to one month. After this period, the data will be deleted, and deleted events cannot be resent
Request
POST /partners/track/webhook/events/{eventId}
Path Variable
| Variable | Type | Description |
|---|---|---|
| eventId | string | Webhook Event ID to resend |
Authentication Headers
| Header | Description |
|---|---|
| tx-clientid | Client ID issued for API integration |
| tx-apikey | API key for client authentication |
Response
200 on success
4xx Error
{
"error_detail": "NOT_FOUND_ENDPOINT",
"transaction_time": "2025-03-20T05:42:27.135265"
}
Duplicate Event Handling
Depending on network conditions or retry policies,
the webhook endpoint may receive the same event multiple times.
Since TRADLINX re-sends with the same event_id during retries,
the receiving (client) endpoint must implement logic to prevent duplicate event processing.
Deduplication Rules
- When receiving an event, record whether the event has already been processed based on
event_id. - If the same
event_idis received again, it is a retried event, so checkoccurred_datetimeto determine whether it is the latest event. - If processing has already been completed for the same
event_id, it must be ignored without re-running business logic.
Recommended Approach
- Record a “processed” status in a database, Redis, or other storage based on
event_id. - If a re-received event exists, ignore it immediately or only log it.