> ## Documentation Index
> Fetch the complete documentation index at: https://terminal49.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Identify Your Carrier with Infer Tracking Number

> Use the Terminal49 Infer Tracking Number endpoint to identify a carrier SCAC from a bill of lading or container number before you create a tracking request.

<Note>
  **Beta Feature** — This guide covers the [Infer Tracking
  Number](/api-docs/api-reference/tracking-requests/auto-detect-carrier)
  endpoint (also known as Auto-Detect Carrier), currently in beta. The API is
  stable for production use, but features may expand based on feedback.
</Note>

Every tracking request requires two things: **your tracking number** and **the shipping line's (carrier's) SCAC code**.
But what if you don't know the SCAC? That's where Infer Tracking Number comes in.

<Card title="Already using the Terminal49 Dashboard?" icon="browser" horizontal>
  You've seen this feature in action — when you enter a number, Terminal49 auto-suggests
  the carrier. Now this same intelligence is available via API.
</Card>

## Why SCAC matters

To track a shipment or container, Terminal49 needs to know **which shipping line to ask** (also called the vessel-operating common carrier (VOCC)).
The SCAC (Standard Carrier Alpha Code) used here is the **shipping line SCAC for tracking** — that is, the carrier operating the move you're querying for events and shipment data.

| You Have                        | You Need                       | The Challenge                                                                                                                        |
| ------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| Bill of Lading: `MAEU123456789` | Shipping line SCAC (VOCC SCAC) | Many MBOLs **do not include a prefix**, and even when they do, it may not reliably identify the shipping line you need for tracking. |
| Container: `WHLU1234560`        | Shipping line SCAC (VOCC SCAC) | The container owner code / leasing company is not always the carrier moving it, so the prefix alone is not enough.                   |
| Booking: `987654321`            | Shipping line SCAC (VOCC SCAC) | Booking formats vary widely and often contain no carrier identifier.                                                                 |

<Info>
  Without the correct **shipping line SCAC (VOCC SCAC)**, your tracking request can fail even if the
  number is valid. Infer Tracking Number predicts the shipping line SCAC + number type to
  increase the likelihood your tracking request succeeds.
</Info>

## How Infer Tracking Number helps

Submit any tracking number, and the API returns:

* **The predicted shipping line (SCAC)** — so you don't have to guess
* **The number type** — container, bill of lading, or booking
* **Validation results** — catches typos and invalid formats before you submit

<Steps>
  <Step title="You submit a tracking number" icon="input-text">
    Just the number — no need to specify the shipping line or type
  </Step>

  <Step title="We analyze the pattern" icon="microchip-ai">
    Our system uses machine learning and historical data from millions of
    shipments to predict the shipping line.
  </Step>

  <Step title="You get the SCAC and confidence score" icon="bullseye-arrow">
    Use high-confidence results automatically, or prompt users to confirm
  </Step>

  <Step title="Create a successful tracking request" icon="check">
    With the right SCAC, your tracking request is far more likely to succeed
  </Step>
</Steps>

## Examples by number type

<Tabs>
  <Tab title="Container Number" icon="box">
    Container numbers follow the ISO 6346 format. While the first three letters (owner code) often indicate the owner, the container might be moved by a different shipping line (VOCC).

    Our system analyzes the number against tens of millions of historical records to predict which shipping line is moving the container.

    **Example Input:** `MSCU1234567`

    <CodeGroup>
      ```json Request theme={null}
      {
        "number": "MSCU1234567"
      }
      ```

      ```json Response theme={null}
      {
        "data": {
          "attributes": {
            "number_type": "container",
            "validation": {
              "is_valid": true,
              "type": "container",
              "check_digit_passed": true
            },
            "shipping_line": {
              "decision": "auto_select",
              "selected": {
                "scac": "MSCU",
                "name": "Mediterranean Shipping Company",
                "confidence": 1.0
              },
              "candidates": [
                {
                  "scac": "MSCU",
                  "name": "Mediterranean Shipping Company",
                  "confidence": 1.0
                }
              ]
            }
          }
        }
      }
      ```
    </CodeGroup>

    <Tip>
      For container numbers, Terminal49 uses historical data to identify the shipping line with high accuracy (9/10 times).
      Always check the `decision` field to know if you should ask the user for confirmation.
    </Tip>

    **What to do next:**

    ```bash theme={null}
    # Create tracking request with the detected SCAC
    POST /tracking_requests
    {
      "data": {
        "type": "tracking_request",
        "attributes": {
          "request_number": "MSCU1234567",
          "scac": "MSCU",
          "request_type": "container"
        }
      }
    }
    ```
  </Tab>

  <Tab title="Bill of Lading" icon="file-lines">
    Bill of lading numbers vary by carrier. Some contain prefixes, but others don't. The API uses machine learning to identify the carrier pattern.

    **Example Input:** `MAEU123456789`

    <CodeGroup>
      ```json Request theme={null}
      {
        "number": "MAEU123456789"
      }
      ```

      ```json Response theme={null}
      {
        "data": {
          "attributes": {
            "number_type": "bill_of_lading",
            "validation": {
              "is_valid": true,
              "type": "shipment"
            },
            "shipping_line": {
              "decision": "auto_select",
              "selected": {
                "scac": "MAEU",
                "name": "Maersk",
                "confidence": 0.98
              },
              "candidates": [
                {
                  "scac": "MAEU",
                  "name": "Maersk",
                  "confidence": 0.98
                }
              ]
            }
          }
        }
      }
      ```
    </CodeGroup>

    <Note>
      Maersk BLs typically start with `MAEU`, but other carriers may not have prefixes. The API analyzes the full format.
    </Note>

    **What to do next:**

    ```bash theme={null}
    # Create tracking request with the detected SCAC
    POST /tracking_requests
    {
      "data": {
        "type": "tracking_request",
        "attributes": {
          "request_number": "MAEU123456789",
          "scac": "MAEU",
          "request_type": "bill_of_lading"
        }
      }
    }
    ```
  </Tab>

  <Tab title="Booking Number" icon="ticket">
    Booking numbers are the **hardest to identify** — they often don't contain carrier identifiers.

    **Example Input:** `987654321`

    <CodeGroup>
      ```json Request theme={null}
      {
        "number": "987654321"
      }
      ```

      ```json Response theme={null}
      {
        "data": {
          "attributes": {
            "number_type": "booking",
            "validation": {
              "is_valid": null,
              "type": "shipment"
            },
            "shipping_line": {
              "decision": "needs_confirmation",
              "selected": {
                "scac": "HLCU",
                "name": "Hapag-Lloyd",
                "confidence": 0.72
              },
              "candidates": [
                {
                  "scac": "HLCU",
                  "name": "Hapag-Lloyd",
                  "confidence": 0.72
                },
                {
                  "scac": "ONE",
                  "name": "Ocean Network Express",
                  "confidence": 0.18
                }
              ]
            }
          }
        }
      }
      ```
    </CodeGroup>

    <Warning>
      When `decision` is `needs_confirmation`, show the suggestion but **ask the user to verify**.
      Display the `candidates` list as options.
    </Warning>

    **What to do next:**

    ```bash theme={null}
    # Show user the suggested carrier and candidates
    # After user confirms, create tracking request
    POST /tracking_requests
    {
      "data": {
        "type": "tracking_request",
        "attributes": {
          "request_number": "987654321",
          "scac": "HLCU",
          "request_type": "booking"
        }
      }
    }
    ```
  </Tab>
</Tabs>

## Understanding the response

<AccordionGroup>
  <Accordion title="Decision Types Explained" icon="code-branch" defaultOpen>
    The `decision` field tells you how confident the prediction is and what action to take:

    | Decision             | When it's used               | What to do                                            |
    | -------------------- | ---------------------------- | ----------------------------------------------------- |
    | `auto_select`        | Confidence ≥ 95%             | ✅ Safe to use automatically without user confirmation |
    | `needs_confirmation` | Confidence 70-95%            | ⚠️ Show suggestion, ask user to confirm               |
    | `no_prediction`      | Confidence \< 70% or unknown | ❌ User must select carrier manually                   |

    <Tip>
      For the best user experience, always handle all three decision types. Even
      when `no_prediction` is returned, you can still show the list of `candidates`
      as suggestions.
    </Tip>
  </Accordion>

  <Accordion title="Validation Fields" icon="shield-check">
    The API validates numbers before returning predictions:

    | Field                | Description                                                      |
    | -------------------- | ---------------------------------------------------------------- |
    | `is_valid`           | `true` if format is valid, `false` if invalid, `null` if unknown |
    | `check_digit_passed` | For containers: ISO 6346 check digit verification                |
    | `reason`             | If invalid, explains why (e.g., "Invalid check digit")           |

    <Info>
      Invalid numbers may still return a carrier prediction, but you should validate
      the format before creating a tracking request.
    </Info>
  </Accordion>

  <Accordion title="Full Response Schema" icon="brackets-curly">
    | Field                      | Type   | Description                                                |
    | -------------------------- | ------ | ---------------------------------------------------------- |
    | `number_type`              | string | Detected type: `container`, `bill_of_lading`, or `booking` |
    | `shipping_line.decision`   | string | Confidence level for the prediction                        |
    | `shipping_line.selected`   | object | Best match: `scac`, `name`, `confidence`                   |
    | `shipping_line.candidates` | array  | All possible matches, ranked by confidence                 |

    See the [API Reference](/api-docs/api-reference/tracking-requests/auto-detect-carrier) for complete schema details.
  </Accordion>
</AccordionGroup>

## Integration guide

For developers implementing this API, here are code examples in different languages:

<Tabs>
  <Tab title="JavaScript" icon="js">
    ```javascript theme={null}
    async function getCarrierForNumber(trackingNumber, apiKey) {
      const response = await fetch(
        "https://api.terminal49.com/v2/tracking_requests/infer_number",
        {
          method: "POST",
          headers: {
            Authorization: `Token ${apiKey}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ number: trackingNumber }),
        }
      );

    const { data } = await response.json();
    const { decision, selected, candidates } = data.attributes.shipping_line;

    return {
    scac: selected?.scac,
    carrier: selected?.name,
    confidence: selected?.confidence,
    autoSelect: decision === "auto_select",
    needsConfirmation: decision === "needs_confirmation",
    candidates: candidates,
    };
    }

    // Usage
    const result = await getCarrierForNumber("MSCU1234567", "YOUR_API_KEY");
    if (result.autoSelect) {
    // Auto-fill carrier dropdown
    carrierDropdown.value = result.scac;
    } else if (result.needsConfirmation) {
    // Show suggestion with confirmation prompt
    showCarrierSuggestion(result.carrier, result.candidates);
    }

    ```
  </Tab>

  <Tab title="Python" icon="python">
    ```python theme={null}
    import requests

    def get_carrier_for_number(tracking_number: str, api_key: str) -> dict:
        """Get carrier prediction for a tracking number."""
        response = requests.post(
            'https://api.terminal49.com/v2/tracking_requests/infer_number',
            headers={
                'Authorization': f'Token {api_key}',
                'Content-Type': 'application/json'
            },
            json={'number': tracking_number}
        )

        result = response.json()
        shipping_line = result['data']['attributes']['shipping_line']

        return {
            'scac': shipping_line['selected']['scac'] if shipping_line.get('selected') else None,
            'carrier': shipping_line['selected']['name'] if shipping_line.get('selected') else None,
            'confidence': shipping_line['selected']['confidence'] if shipping_line.get('selected') else None,
            'auto_select': shipping_line['decision'] == 'auto_select',
            'needs_confirmation': shipping_line['decision'] == 'needs_confirmation',
            'candidates': shipping_line.get('candidates', [])
        }

    # Usage
    result = get_carrier_for_number("MSCU1234567", "YOUR_API_KEY")
    if result['auto_select']:
        # Auto-fill carrier dropdown
        carrier_dropdown.value = result['scac']
    elif result['needs_confirmation']:
        # Show suggestion with confirmation prompt
        show_carrier_suggestion(result['carrier'], result['candidates'])
    ```
  </Tab>

  <Tab title="cURL" icon="terminal">
    ```bash theme={null}
    curl -X POST https://api.terminal49.com/v2/tracking_requests/infer_number \
      -H "Authorization: Token YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"number": "MSCU1234567"}'
    ```
  </Tab>
</Tabs>

## Rate limits

| Setting             | Value                                       |
| ------------------- | ------------------------------------------- |
| Requests per minute | 200                                         |
| Scope               | Per API key, in an endpoint-specific bucket |
| Rate limit header   | `Retry-After` (seconds)                     |

<Warning>
  Rate limit errors return HTTP 429 with a `Retry-After` header. Respect this
  header before sending another Infer Tracking Number request.
</Warning>

## What's next?

<CardGroup cols={2}>
  <Card title="Infer Tracking Number API Reference" icon="code" href="/api-docs/api-reference/tracking-requests/auto-detect-carrier">
    Full API specification with request/response schemas and try it in the
    playground
  </Card>

  <Card title="Create a Tracking Request" icon="circle-plus" href="/api-docs/api-reference/tracking-requests/create-a-tracking-request">
    Use the detected SCAC to start tracking your shipment
  </Card>

  <Card title="Supported Carriers" icon="ship" href="/api-docs/useful-info/api-data-sources-availability">
    See which carriers Terminal49 supports and their data availability
  </Card>

  <Card title="Tracking Request Lifecycle" icon="arrows-spin" href="/api-docs/in-depth-guides/tracking-request-lifecycle">
    Learn what happens after you submit a tracking request
  </Card>
</CardGroup>
