Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
644 changes: 322 additions & 322 deletions Terminal49-API.postman_collection.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ openapi: post /tracking_requests
---

<Tip>
**Don't know the SCAC?** Call [Infer Tracking
Number](/api-docs/api-reference/tracking-requests/auto-detect-carrier)
(Auto-Detect Carrier) first to identify the shipping line from your tracking
number.
**Don't know the SCAC?** Set `auto_detect_vocc_scac` to `true` and omit `scac`,
and Terminal49 will infer the shipping line for you. Detection runs
asynchronously: the request is created immediately with `status: "pending"` and
`scac: null`, then resolves to `created` (with the detected `scac` populated) or
`failed` (`failed_reason: "scac_auto_detect_failed"`) — poll the tracking request
or use webhooks to observe the outcome. Use [Auto-Detect
Carrier](/api-docs/api-reference/tracking-requests/auto-detect-carrier) first
when your workflow needs to preview or confirm carrier candidates before
submitting.
</Tip>

<Info>
Expand Down
30 changes: 26 additions & 4 deletions docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1308,10 +1308,17 @@
},
"scac": {
"type": "string",
"description": "The carrier SCAC to use for this tracking request. Required unless `auto_detect_vocc_scac` is `true`.",
"example": "MSCU",
"minLength": 4,
"maxLength": 4
},
"auto_detect_vocc_scac": {
"type": "boolean",
"description": "Set to `true` to have Terminal49 infer the carrier SCAC from `request_number` when `scac` is not supplied. Detection is asynchronous: the tracking request is created immediately (HTTP `201`) with `status: \"pending\"` and `scac: null`. If a carrier is inferred, the request transitions to `status: \"created\"` with the detected `scac` populated. If no supported carrier can be inferred, it transitions to `status: \"failed\"` with `failed_reason: \"scac_auto_detect_failed\"` and no shipment is created. Poll the tracking request or use webhooks to observe the outcome — the create response does not include the detected `scac`.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make auto-detect responses allow null SCAC

When auto-detect is used, this new description says the 201 response can return status: "pending" with scac: null, but the response still references #/components/schemas/tracking_request, whose attributes.scac remains a required string. Generated clients or validators built from this OpenAPI will reject or mis-type valid pending/failed auto-detect responses, so the tracking request response schema needs to allow a null or absent SCAC for those states.

Useful? React with 👍 / 👎.

"default": false,
"example": true
Comment on lines +1316 to +1320

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Regenerate the exported OpenAPI types

Adding auto_detect_vocc_scac to the source OpenAPI without updating sdks/typescript-sdk/src/generated/terminal49.ts leaves the SDK's exported paths type stale: it still has no auto_detect_vocc_scac field for POST /tracking_requests and still requires scac: string. Consumers using the exported OpenAPI types or an openapi-fetch client built from them cannot compile the valid auto-detect request that the docs and helper now support, so the generated type file needs to be brought back in sync with this schema change.

Useful? React with 👍 / 👎.

},
"ref_numbers": {
"type": "array",
"description": "Optional list of reference numbers to be added to the shipment when tracking request completes",
Expand All @@ -1329,8 +1336,7 @@
},
"required": [
"request_type",
"request_number",
"scac"
"request_number"
]
Comment on lines 1337 to 1340

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Missing Conditional SCAC Requirement

With scac removed from required, the schema accepts a create request that has only request_type and request_number. That conflicts with the documented contract that callers must supply either scac or auto_detect_vocc_scac: true, so generated clients and validators can now allow a request the API is expected to reject.

Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/openapi.json
Line: 1346-1349

Comment:
**Missing Conditional SCAC Requirement**

With `scac` removed from `required`, the schema accepts a create request that has only `request_type` and `request_number`. That conflicts with the documented contract that callers must supply either `scac` or `auto_detect_vocc_scac: true`, so generated clients and validators can now allow a request the API is expected to reject.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex

Comment on lines 1337 to 1340

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require either SCAC or auto-detect in the schema

With the required list now only containing request_type and request_number, the OpenAPI contract accepts a tracking-request payload that has neither scac nor auto_detect_vocc_scac. The new endpoint text says callers must supply either a carrier SCAC or set auto-detect to true, so clients/validators generated from docs/openapi.json can now pass requests the API will reject; please model the conditional requirement, e.g. with oneOf/anyOf requiring scac or auto_detect_vocc_scac: true, instead of dropping scac outright.

Useful? React with 👍 / 👎.

},
"relationships": {
Expand Down Expand Up @@ -1399,6 +1405,21 @@
"type": "tracking_request"
}
}
},
"Example: Auto-detect carrier SCAC": {
"value": {
"data": {
"attributes": {
"request_type": "bill_of_lading",
"request_number": "MEDUFR030802",
"auto_detect_vocc_scac": true,
"ref_numbers": [
"PO12345"
]
},
"type": "tracking_request"
}
}
}
}
}
Expand All @@ -1410,7 +1431,7 @@
"authorization": []
}
],
"description": "To track an ocean shipment, you create a new tracking request. \nTwo attributes are required to track a shipment. A `bill of lading/booking number` and a shipping line `SCAC`. \n\nOnce a tracking request is created we will attempt to fetch the shipment details and it's related containers from the shipping line. If the attempt is successful we will create in new shipment object including any related container objects. We will send a `tracking_request.succeeded` webhook notification to your webhooks. \n\nIf the attempt to fetch fails then we will send a `tracking_request.failed` webhook notification to your `webhooks`. \n\nA `tracking_request.succeeded` or `tracking_request.failed` webhook notificaiton will only be sent if you have atleast one active webhook. <br /><br /><Info>This endpoint is limited to 100 tracking requests per minute.</Info>",
"description": "To track an ocean shipment, create a new tracking request. `request_type` and `request_number` are always required. Supply either a shipping line `scac` or set `auto_detect_vocc_scac` to `true` to have Terminal49 infer the SCAC from the request number before creating the tracking request.\n\nAuto-detection uses the same carrier prediction capability as the Infer Tracking Number endpoint and runs asynchronously. The tracking request is created immediately (HTTP `201`) with `status: \"pending\"`; if no supported carrier can be inferred it transitions to `status: \"failed\"` with `failed_reason: \"scac_auto_detect_failed\"` and no shipment is created. Once a tracking request is created we will attempt to fetch the shipment details and its related containers from the shipping line. If the attempt is successful we will create a new shipment object including any related container objects. We will send a `tracking_request.succeeded` webhook notification to your webhooks.\n\nIf the attempt to fetch fails then we will send a `tracking_request.failed` webhook notification to your `webhooks`.\n\nA `tracking_request.succeeded` or `tracking_request.failed` webhook notification will only be sent if you have at least one active webhook. <br /><br /><Info>This endpoint is limited to 100 tracking requests per minute.</Info>",
"tags": [
"Tracking Requests"
],
Expand Down Expand Up @@ -12131,9 +12152,10 @@
"shipping_line_unreachable",
"unrecognized_response",
"data_unavailable",
"scac_auto_detect_failed",
null
],
"description": "If the tracking request has failed, or is currently failing, the last reason we were unable to complete the request",
"description": "If the tracking request has failed, or is currently failing, the last reason we were unable to complete the request. `scac_auto_detect_failed` means `auto_detect_vocc_scac` was set but no supported carrier SCAC could be inferred from the request number.",
"nullable": true
},
"request_type": {
Expand Down
8 changes: 5 additions & 3 deletions docs/sdk/reference/client/classes/Terminal49Client.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ data from Node.js applications.

> **createTrackingRequest**(`params`): `Promise`\<`any`\>

Create a tracking request with an explicit number type and carrier SCAC.
Create a tracking request with an explicit number type and carrier SCAC, or ask the API to auto-detect the carrier SCAC.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `params` | \{ `refNumbers?`: `string`[]; `requestNumber`: `string`; `requestType`: [`TrackingRequestType`](/sdk/reference/client/managers/type-aliases/TrackingRequestType); `scac?`: `string`; `shipmentTags?`: `string`[]; \} |
| `params` | \{ `autoDetectVoccScac?`: `boolean`; `refNumbers?`: `string`[]; `requestNumber`: `string`; `requestType`: [`TrackingRequestType`](/sdk/reference/client/managers/type-aliases/TrackingRequestType); `scac?`: `string`; `shipmentTags?`: `string`[]; \} |
| `params.autoDetectVoccScac?` | `boolean` |
| `params.refNumbers?` | `string`[] |
| `params.requestNumber` | `string` |
| `params.requestType` | [`TrackingRequestType`](/sdk/reference/client/managers/type-aliases/TrackingRequestType) |
Expand Down Expand Up @@ -471,7 +472,8 @@ Convenience helper for creating a tracking request from a container or booking n

| Parameter | Type |
| ------ | ------ |
| `params` | \{ `bookingNumber?`: `string`; `containerNumber?`: `string`; `refNumbers?`: `string`[]; `scac?`: `string`; \} |
| `params` | \{ `autoDetectVoccScac?`: `boolean`; `bookingNumber?`: `string`; `containerNumber?`: `string`; `refNumbers?`: `string`[]; `scac?`: `string`; \} |
| `params.autoDetectVoccScac?` | `boolean` |
| `params.bookingNumber?` | `string` |
| `params.containerNumber?` | `string` |
| `params.refNumbers?` | `string`[] |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ description: "TrackingRequestManager in the Terminal49 TypeScript SDK, used to c

| Parameter | Type |
| ------ | ------ |
| `params` | \{ `refNumbers?`: `string`[]; `requestNumber`: `string`; `requestType`: [`TrackingRequestType`](/sdk/reference/client/managers/type-aliases/TrackingRequestType); `scac?`: `string`; `shipmentTags?`: `string`[]; \} |
| `params` | \{ `autoDetectVoccScac?`: `boolean`; `refNumbers?`: `string`[]; `requestNumber`: `string`; `requestType`: [`TrackingRequestType`](/sdk/reference/client/managers/type-aliases/TrackingRequestType); `scac?`: `string`; `shipmentTags?`: `string`[]; \} |
| `params.autoDetectVoccScac?` | `boolean` |
| `params.refNumbers?` | `string`[] |
| `params.requestNumber` | `string` |
| `params.requestType` | [`TrackingRequestType`](/sdk/reference/client/managers/type-aliases/TrackingRequestType) |
Expand Down
58 changes: 58 additions & 0 deletions sdks/typescript-sdk/src/client.request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,64 @@ describe('Terminal49Client request building', () => {
expect(calls[1].url.searchParams.get('include')).toBe('shipment,container');
});

it('sends explicit scac when creating tracking request', async () => {
let captured: any = null;
const { fetchImpl } = createMockFetch({
'/tracking_requests': (init) => {
captured = JSON.parse(String(init?.body));
return jsonResponse({ data: { id: 'tr-1' } }, 201);
},
});

const client = new Terminal49Client({
apiToken: 'token-123',
apiBaseUrl: baseUrl,
fetchImpl,
});

await client.createTrackingRequest({
requestType: 'bill_of_lading',
requestNumber: 'MEDUFR030802',
scac: 'MSCU',
});

expect(captured.data.attributes).toMatchObject({
request_type: 'bill_of_lading',
request_number: 'MEDUFR030802',
scac: 'MSCU',
});
expect(captured.data.attributes.auto_detect_vocc_scac).toBeUndefined();
});

it('sends auto_detect_vocc_scac without blank scac when requested', async () => {
let captured: any = null;
const { fetchImpl } = createMockFetch({
'/tracking_requests': (init) => {
captured = JSON.parse(String(init?.body));
return jsonResponse({ data: { id: 'tr-2' } }, 201);
},
});

const client = new Terminal49Client({
apiToken: 'token-123',
apiBaseUrl: baseUrl,
fetchImpl,
});

await client.createTrackingRequest({
requestType: 'bill_of_lading',
requestNumber: 'MEDUFR030802',
autoDetectVoccScac: true,
});

expect(captured.data.attributes).toMatchObject({
request_type: 'bill_of_lading',
request_number: 'MEDUFR030802',
auto_detect_vocc_scac: true,
});
expect(captured.data.attributes.scac).toBeUndefined();
});

it('sends JSON:API payload for updateTrackingRequest', async () => {
let captured: any = null;
const { fetchImpl } = createMockFetch({
Expand Down
5 changes: 4 additions & 1 deletion sdks/typescript-sdk/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ export class Terminal49Client {
containerNumber?: string;
bookingNumber?: string;
scac?: string;
autoDetectVoccScac?: boolean;
refNumbers?: string[];
}): Promise<any> {
const requestType: TrackingRequestType = params.containerNumber
Expand All @@ -196,15 +197,17 @@ export class Terminal49Client {
requestType,
requestNumber,
scac: params.scac,
autoDetectVoccScac: params.autoDetectVoccScac,
refNumbers: params.refNumbers,
});
}

/** Create a tracking request with an explicit number type and carrier SCAC. */
/** Create a tracking request with an explicit number type and carrier SCAC, or ask the API to auto-detect the carrier SCAC. */
async createTrackingRequest(params: {
requestType: TrackingRequestType;
requestNumber: string;
scac?: string;
autoDetectVoccScac?: boolean;
refNumbers?: string[];
shipmentTags?: string[];
}): Promise<any> {
Expand Down
22 changes: 15 additions & 7 deletions sdks/typescript-sdk/src/client/managers/tracking-requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export class TrackingRequestManager extends BaseManager {
requestType: TrackingRequestType;
requestNumber: string;
scac?: string;
autoDetectVoccScac?: boolean;
refNumbers?: string[];
shipmentTags?: string[];
}): Promise<any> {
Expand All @@ -119,16 +120,23 @@ export class TrackingRequestManager extends BaseManager {
);
}

const attributes: Record<string, unknown> = {
request_type: params.requestType,
request_number: params.requestNumber,
scac: params.scac ?? '',
ref_numbers: params.refNumbers,
shipment_tags: params.shipmentTags,
};

if (params.autoDetectVoccScac) {
attributes.auto_detect_vocc_scac = true;
if (!params.scac) delete attributes.scac;
}
Comment on lines +131 to +134

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Conflicting SCAC Detection Payload

When callers pass both autoDetectVoccScac: true and a non-empty scac, this branch sends both auto_detect_vocc_scac and scac. The documented auto-detect contract applies when scac is not supplied, so this reachable SDK call can produce an ambiguous request that the API may reject or resolve differently than the caller intended.

Prompt To Fix With AI
This is a comment left during a code review.
Path: sdks/typescript-sdk/src/client/managers/tracking-requests.ts
Line: 131-134

Comment:
**Conflicting SCAC Detection Payload**

When callers pass both `autoDetectVoccScac: true` and a non-empty `scac`, this branch sends both `auto_detect_vocc_scac` and `scac`. The documented auto-detect contract applies when `scac` is not supplied, so this reachable SDK call can produce an ambiguous request that the API may reject or resolve differently than the caller intended.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex

Comment on lines +131 to +134

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid sending SCAC with auto-detect requests

When callers pass both autoDetectVoccScac: true and a non-empty scac, this branch sends both auto_detect_vocc_scac and scac because scac is only deleted when it is falsy. The documented contract says auto-detect applies when scac is omitted and callers should supply either field, so this reachable SDK call can produce an ambiguous payload that may be rejected or treated as an explicit-SCAC request instead of auto-detect; reject the combination or omit scac whenever auto-detect is requested.

Useful? React with 👍 / 👎.


const payload = {
data: {
type: 'tracking_request' as const,
attributes: {
request_type: params.requestType,
request_number: params.requestNumber,
scac: params.scac ?? '',
ref_numbers: params.refNumbers,
shipment_tags: params.shipmentTags,
},
attributes,
},
};

Expand Down
Loading