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

# TypeScript SDK

> Install, configure, and call every LandedFees v1 endpoint from Node 18+, Bun, Deno, or the browser (server-only).

## Install

```bash theme={null}
pnpm add @landedfees/sdk
# or
npm install @landedfees/sdk
# or
yarn add @landedfees/sdk
```

Node 18 or higher. Works in Bun, Deno, and modern edge runtimes.

<Warning>
  Never ship an API key to the browser. Call the SDK from a server
  route (Next.js Route Handlers, tRPC procedures, Express endpoints)
  and proxy the response to your client.
</Warning>

## Quick start

```ts theme={null}
import { LandedFeesClient } from "@landedfees/sdk";

const client = new LandedFeesClient({
  apiKey: process.env.LANDEDFEES_API_KEY!,
});

const { result, compliance_flags } = await client.calc({
  destination_country: "US",
  origin_country: "CN",
  incoterm: "FOB",
  transport_mode: "ocean",
  currency: "USD",
  freight: 250,
  insurance: 45,
  line_items: [
    {
      description: "Wireless earbuds",
      hs_code: "8517.62.00",
      quantity: 500,
      unit_value: 12.5,
      origin_country: "CN",
      weight_kg: 0.15,
    },
  ],
});

console.log(result.total_landed_cost, result.currency);
```

## Full method surface

```ts theme={null}
client.calc(body, options?)
client.calcBulk(body, options?)
client.classify(body, options?)
client.compare(body, options?)
client.rates(country, hs, query?, options?)
```

Every method returns a typed promise. See [`src/types.ts`](https://github.com/landedfees/sdk-typescript/blob/main/src/types.ts)
for the full type surface.

## Constructor options

```ts theme={null}
new LandedFeesClient({
  apiKey: string,
  baseUrl?: string,          // default: "https://www.landedfees.com"
  timeoutMs?: number,        // default: 30_000
  maxRetries?: number,       // default: 1
  fetch?: typeof fetch,      // inject a custom fetch (undici, tests)
  userAgent?: string,        // default: "@landedfees/sdk@0.1"
});
```

## Idempotency

Pass `idempotencyKey` in options to make retries safe.

```ts theme={null}
import { randomUUID } from "node:crypto";

const idempotencyKey = randomUUID();
const first  = await client.calc(payload, { idempotencyKey });
const second = await client.calc(payload, { idempotencyKey });
// first.id === second.id
```

## Error handling

Non-2xx responses throw `ApiError` with the status, machine `code`,
parsed body, and `retryAfter` (populated on `429`).

```ts theme={null}
import { ApiError } from "@landedfees/sdk";

try {
  await client.calc(payload);
} catch (err) {
  if (err instanceof ApiError) {
    if (err.status === 429) {
      await new Promise((r) => setTimeout(r, (err.retryAfter ?? 60) * 1000));
    } else if (err.status === 422 && err.code === "MISSING_HS_CODE") {
      // Run classify first.
    } else {
      throw err;
    }
  }
}
```

The client retries once by default on `429` and `5xx`. Set
`maxRetries: 0` on the constructor to disable.

## Types

The full request and response shapes are typed. Some highlights:

```ts theme={null}
import type {
  CalcRequest,
  CalcResponse,
  ClassificationResult,
  CompareResponse,
  RatesResponse,
  ComplianceFlag,
  CostLayer,
} from "@landedfees/sdk";
```

## Edge runtime notes

The SDK uses the global `fetch`. On Vercel Edge and Cloudflare
Workers, no additional configuration is needed. On Node 16 (which
does not have global fetch), inject `undici`:

```ts theme={null}
import { fetch } from "undici";
import { LandedFeesClient } from "@landedfees/sdk";

const client = new LandedFeesClient({ apiKey: process.env.KEY!, fetch });
```

Node 18+ has native fetch; no injection required.

## Repository and issues

* Source: [github.com/landedfees/sdk-typescript](https://github.com/landedfees/sdk-typescript)
* Issues: [github.com/landedfees/sdk-typescript/issues](https://github.com/landedfees/sdk-typescript/issues)
* License: Apache-2.0
