Skip to content

Guides

SDKs and clients

Generate a typed client from the OpenAPI spec, or call the API directly with the snippets.

Official SDKs are on the way. Until they land, two paths get you a clean, typed integration today.

Generate a client from the OpenAPI spec

TrackingMCP, SchedulesMCP and LoadingMCP each publish an OpenAPI spec (linked from their reference overview). Point a generator at it and get a typed client in your language.

npx @openapitools/openapi-generator-cli generate \
  -i https://trackingmcp.com/openapi.json \
  -g typescript-fetch \
  -o ./navo-tracking-client

Swap -g for python, go, java or any target the generator supports. The spec is the source of truth, so a regenerate keeps your client in step with the API.

Or call it directly

Every endpoint in the reference ships copy-paste samples in curl, JavaScript and Python. For most integrations a thin fetch or requests wrapper is all you need.

POST /v1/containers takes two required fields, identifier and identifier_type. Send one without the other, or send neither, and you get a 400 with VALIDATION_ERROR.

const NAVO_KEY = process.env.NAVO_KEY;

// identifierType is one of "container_id", "bill_of_lading" or "booking".
async function track(identifier, identifierType = "container_id") {
  const res = await fetch("https://api.trackingmcp.com/v1/containers", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${NAVO_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      identifier,
      identifier_type: identifierType,
      // carrier_code is optional. Omit it and we resolve the line from the prefix.
    }),
  });
  if (!res.ok) throw new Error(`Navo ${res.status}`);
  return res.json();
}

A successful add answers 201 with the record we opened:

{
  "ok": true,
  "data": {
    "id": "8f1c2d4e-6a3b-4f52-9c70-11ab22cd33ef",
    "identifier": "MEDU1234562",
    "status": "in_transit",
    "carrier_code": "MSCU",
    "source": "direct_carrier"
  }
}
  • id is the container UUID. Keep it: every other container endpoint is keyed on it.
  • status is the normalised status. A box we accepted but could not resolve on the first pass comes back as unknown, alongside a warning string, and resolves within minutes as the re-poll runs.
  • carrier_code is the SCAC we resolved. An unresolved add carries UNRESOLVED_CARRIER until a later poll names the line.
  • source says which path answered: direct_carrier, searates or warm_db.

Keep the key on your backend, read it from the environment, and branch on the status code. See errors and rate limits.

Let a model call the tools

If an assistant is doing the work, skip the client entirely and wire the MCP server. See the MCP quickstart.