# Calculate a whole shipment (POST /v1/calculate/shipment)

> POST /v1/calculate/shipment: Calculate a whole shipment. border.bot API reference (Landed cost).

Source: https://staging.border.bot/docs/api/calculate-shipment

> Documentation index: https://staging.border.bot/llms.txt. Every page is Markdown at its URL + `.md`.

`POST https://staging-api.border.bot/v1/calculate/shipment`

Requires an API key (`Authorization: Bearer bb_live_…`).

Duties, taxes, fees and the landed cost of a cart or order to one destination: up to 50 lines (by their facts, or catalogue products by `sku`), freight and insurance shared out by value, one de minimis check, and per-entry fees charged once. Costs 1 credit per line. Priced on border.bot’s own data: a destination it doesn’t cover yet returns 422 `unsupported_country` without charging.

API key scope: `calculate`.

## Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `idempotency-key` | string | no | Make retries safe: a repeat with the same key returns the original result without charging again (keys are scoped to your workspace). |

## Request body (JSON)

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `destinationCountry` | string | yes | Destination: one `GET /countries` marks `landedCost`. ISO 3166-1 alpha-2, case-insensitive. |
| `currency` | string | no | ISO 4217 currency of `value`, `shippingCost` and `insuranceCost`. |
| `shippingCost` | number | no | Shipping cost (affects CIF-based duty/VAT bases). |
| `insuranceCost` | number | no | Insurance cost. |
| `transportMode` | "air" \| "sea" \| "road" \| "rail" | no | Transport mode (fees such as HMF apply to sea freight). |
| `shippingTerms` | "EXW" \| "FCA" \| "FAS" \| "FOB" \| "CFR" \| "CIF" \| "CPT" \| "CIP" \| "DAP" \| "DPU" \| "DDP" | no | Incoterm of the price (Incoterms 2020). Under C and D terms (CFR, CIF, CPT, CIP, DAP, DPU, DDP) the price already carries the goods to the destination, so `shippingCost` isn’t added to the customs value again. |
| `shipmentChannel` | "courier" \| "postal" \| "freight" | no | How the goods travel and clear: `courier` (an express consignment: DHL, UPS, FedEx…), `postal` (national post) or `freight` (cargo on its own entry). Omitted: from `transportMode` — air is `courier`, sea, road and rail are `freight` (sea cargo is never an express consignment, so `courier` by sea is priced as freight). Affects de minimis and fees (US: the informal-entry MPF, 19 CFR 24.23(b)(2), is charged on freight; express consignments pay the carrier’s per-waybill fee, 24.23(b)(4)). The result’s `shipmentChannel` says which was used. |
| `entryDate` | string | no | Calculate with the rates in force on this date (YYYY-MM-DD). Default: today. |
| `tradeAgreement` | string | no | Ignored. Preferential rates are applied automatically from the origin and destination; the agreement used is returned as `tradeAgreement`. |
| `region` | string | no | State, province or territory, where import taxes differ inside the country. Canada needs one (`ON`, `QC`, `BC`…). |
| `purpose` | "sale" \| "gift" \| "sample" \| "return" | no | Why the goods are sent: some thresholds differ for gifts, samples and returns. Default: `sale`. A `gift` is a personal gift, not something bought: a free gift with a purchase is `sale` (or set `giftInConjunctionWithPurchase`). |
| `sender` | "person" \| "business" | no | Who sends the goods: a private `person` or a `business`. Gift exemptions are usually for gifts from a person (US: up to $100 per recipient per day, 19 CFR 10.152); a gift from a business qualifies only on the declaration the destination accepts, claimed in `claims` (US: `gift_statement`, the parcel clearly marked as a gift with a statement enclosed, 19 CFR 10.153(c)). Left out, a gift exemption limited to some senders is applied and the result is `estimated`. |
| `giftInConjunctionWithPurchase` | boolean | no | The gift is given in conjunction with a purchase (a bonus or free article with an order). It isn’t a gift for customs (US 19 CFR 10.153(a)): gift exemptions don’t apply and the goods are treated as sold. |
| `businessBuyer` | boolean | no | The buyer is a business: some taxes are reverse-charged or apply differently. |
| `sellerRegistrations` | string[] | no | Tax schemes the seller is registered for (`EU_IOSS`, `GB_VAT`, `AU_GST`, `NZ_GST`, `NO_VOEC`…). Taxes the seller collects at checkout are returned with `collectedBy: "seller"`. |
| `preference` | string | no | `best` (default): the lowest preferential rate the origin qualifies for. `none`: the general rate only. Or a programme code (`S` for USMCA into the US). Every option is returned in `options`. |
| `claims` | string[] | no | Exemption, relief and quota codes being claimed (US Chapter 99 exclusions such as `9903.88.69`; an end-use authorisation such as TARIC document `N990`; a tariff quota order number such as `050331`). Codes you could claim are returned in `claims.available`. |
| `enforceValidation` | boolean | no | Refuse a shipment that matches one of the destination’s `reject` validation rules (400 `invalid_input`, `details.reason: "validation_failed"`, refunded) instead of reporting it in `validation`. |
| `declarationType` | "full" \| "simplified" | no | The declaration the goods are entered on, when known: `full` (US formal entry) or `simplified` (US informal entry). Default: what the destination’s value rules require. A full declaration may always be chosen; a simplified one the value rules out is ignored (see `notes`). Fees differ by declaration (US MPF, the cotton assessment). |
| `filing` | object | no | How the declaration is filed, when known: `method` `electronic` or `paper`, `preparedBy` `declarant` or `authority` (a customs officer). Default: the destination’s usual filing (electronic, by the declarant). The US informal-entry MPF differs by both. |
| `items` | object[] | yes | The shipment’s lines (up to 50), each with its code, origin and line value, or a catalogue `sku` (or `productId`) and `quantity`. Freight and insurance are shared out by value. |

## Responses

- `200`: The shipment’s landed cost, line by line, and the credits charged. (`CalculateShipmentResponse`)
- `400`: Invalid input (`invalid_input`). (`Error`)
- `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`)
- `402`: Not enough credits (`insufficient_credits`). Nothing was charged. (`Error`)
- `403`: Workspace suspended, action disabled, or the key lacks the scope (`org_suspended`, `action_disabled`, `forbidden`). (`Error`)
- `409`: A request with this Idempotency-Key is still in progress (`conflict`). (`Error`)
- `422`: Destination not covered by border.bot’s own data (`unsupported_country`). (`Error`)
- `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`)
- `500`: Unexpected error (`internal`). (`Error`)
- `502`: The engine failed (`upstream_error`). The credits are refunded automatically. (`Error`)
- `504`: The engine timed out (`upstream_timeout`). The credits are refunded automatically. (`Error`)

## Example

```bash
curl -X POST 'https://staging-api.border.bot/v1/calculate/shipment' \
  -H 'Authorization: Bearer bb_live_...' \
  -H 'Content-Type: application/json' \
  -d '{"destinationCountry":"GB","currency":"USD","shippingCost":12,"items":[{"hsCode":"6109.10","originCountry":"CN","value":60,"quantity":3},{"hsCode":"6204.62","originCountry":"BD","value":45}]}'
```
