> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.trysend.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.trysend.com/_mcp/server.

# Package API (v1)

REST API for managing **parcel customers** (sender profiles), listing and tracking **parcels**, and creating, rating, and purchasing **parcel quotes**.

This page summarizes authentication and test vs live mode.

## Base URL

```
https://api.trysend.com/v1
```

## Authentication

Send your API key on every request:

```http
X-Api-Key: <YOUR_API_KEY>
```

### Test vs live mode

* **Test:** use your **test** API key. Only packages with `mode: "test"` are returned or accepted.
* **Live:** use your **live** API key. Only packages with `mode: "live"` are returned or accepted.

Mode is determined by the key; you do not pass a separate mode header.

## Endpoints (summary)

| Area                 | Operations                              |
| -------------------- | --------------------------------------- |
| **Packages**         | List, get by id, track, create shipment |
| **Parcel quotes**    | List, create (rates), get               |
| **Parcel customers** | List, create, get                       |

Full request/response shapes and status codes are in **API Reference**.

## Response shapes (summary)

Fields vary by **`transport_mode`** (`air` | `ocean`) and **`direction`** (`import` | `export`). Below is what each resource returns.

### Parcel customer — sender profile

`parcel_customer_id`, `uuid`, `first_name`, `last_name`, `email`, `mobile`, `address_suffix` (unique ID), `full_name`, `status` (`active`/`inactive`), `mode` (`test`/`live`), `origin_address`, `origin_city`, `origin_state`, `origin_zip_code`, `origin_country`, `created_at`.

Reusable across quotes and bookings. Link with `address_suffix` or `parcel_customer_token` in parcel quote create.

### Package (Parcel) — warehouse inventory

Created when a booked import quote is received in Virtual Warehouse (Incoming), or when an export air quote is purchased.

`parcel_id`, `parcel_number`, `customer_identifier`, `status`, `trade_direction`, `mode`, `origin_country`, `destination_country`, `created_at`, hold/storage/notices, etc.

| Mode      | Cargo fields                                                                        |
| --------- | ----------------------------------------------------------------------------------- |
| **Air**   | `declared_weight`, `actual_weight`, `length`, `width`, `height`, `volume` (kg / cm) |
| **Ocean** | `quantity` (containers/pieces), `volume`; container summary from linked quote       |

Tracking (`GET /packages/{id}/track`) only applies once the parcel is on a shipment.

### Parcel quote — rating and booking

`parcel_quote_id`, `status`, `reference`, `direction`, `sender`, `recipient`, `created_at`, plus mode-specific cargo and pricing:

|             | **Air**                                                                                 | **Ocean**                                                                                                           |
| ----------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| **Cargo**   | `packages[]` — `package_type`, weight, dimensions (cm); `cargo_volume` e.g. `120 kg`    | Fixed containers: `20'`, `40'`, `40' HC`, `40' REEF`, `20' REEF` per container; LCL per CBM; Ro-Ro/Breakbulk per RT |
| **Pending** | Export: `rates[]` (carrier options). Import: `rates[]` empty                            | Single `Ocean Freight` rate until `create_shipment`                                                                 |
| **Booked**  | Export air: `tracking_code`, `label_url`, `selected_rate`; import air: intake confirmed | Ocean: `selected_rate`, `estimated_price`                                                                           |

Customer `estimated_price` may change at warehouse receive for intake quotes.

Use **`GET /v1/parcel_quotes/:id`** to refresh pending rates. Export air re-rates automatically; ocean recomputes after 1 hour.

### Rate — pick one to ship

Always: `id` (pass to `create_shipment`), `carrier`, `service`, `rate`, `currency`.

| Source         | Typical fields                                                                                                                                             |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Export air** | Multiple carrier options; `estimated_delivery_days`, `estimated_delivery_date`                                                                             |
| **Ocean**      | Single estimate; `estimated_delivery_days` **11**, `estimated_delivery_date`; typical transit 10–12 days, up to **14** worst case; `created_at` for expiry |

All parcel quotes are `pending` on create and move to `booked` through `create_shipment`.

## Errors

| Status | Meaning                                                                                    |
| ------ | ------------------------------------------------------------------------------------------ |
| `401`  | Missing or invalid API key                                                                 |
| `404`  | Resource not found (e.g. unknown package or quote id)                                      |
| `422`  | Validation or business rule failure (body often includes `errors` array or `error` string) |

## Parcel quotes — modes and flows

Create quotes with `POST /v1/parcel_quotes`. Set **`direction`** (`import` | `export`) and **`transport_mode`** (`air` | `ocean`).

| direction | transport\_mode | Result                                                                 |
| --------- | --------------- | ---------------------------------------------------------------------- |
| `export`  | `air`           | Carrier rates → `pending` → purchase with `create_shipment`            |
| `import`  | `air`           | Warehouse intake → `pending` → confirm with `create_shipment`          |
| `import`  | `ocean`         | Single Ocean Freight rate → `pending` → confirm with `create_shipment` |
| `export`  | `ocean`         | Single Ocean Freight rate → `pending` → confirm with `create_shipment` |

### Identify the customer

Use **one** of (all refer to the same parcel customer record):

* `address_suffix` — customer **unique ID** (recommended), e.g. `YSDX-UGTE-1234`
* `parcel_customer_token` — internal token **or** the same unique ID (`YSDX-UGTE-1234` or short `1234`)
* `sender.name` — same as the unique ID
* Full `sender` — name, phone, email, address

If you send both `address_suffix` and `parcel_customer_token`, the token takes precedence.

### Last-mile delivery

Provide destination with flat `dest_*` fields **or** nested `recipient`:

* **Last mile on** — customer's full delivery address in Nigeria
* **Last mile off** — your business or warehouse address (cargo stops at your facility)

Import ocean origin (China warehouse) and sender contact are applied automatically from the linked parcel customer. Provide destination with flat `dest_*` fields **or** nested `recipient`:

### Cargo fields

* **Import air** — `packages[]` with `package_type`, `weight`, `length`, `width`, `height` (cm) per cargo row
* **Export air** — `package` (`weight`, dimensions, `item_description`)
* **Ocean** — `packages[]` with `container_size`, `quantity`, and `commodity` per row. Use the exact fixed-container values `20'`, `40'`, `40' HC`, `40' REEF`, or `20' REEF`; these are priced per container. LCL is priced per CBM and requires `volume` or complete dimensions. Ro-Ro and Breakbulk are priced per RT and require `weight`, plus `volume` or complete dimensions.

Import ocean FCL pricing uses USD rates per container converted to NGN. LCL is priced per CBM. Ro-Ro and Breakbulk are priced per RT, calculated as the greater of CBM and metric tonnes.

## Notes

* IDs in paths are **tokens** (e.g. `parcel_id`, `parcel_quote_id`), not numeric database ids.
* Tracking is only populated for packages that are assigned to a shipment.
* List packages supports optional query `status`: `booked`, `warehouse`, `transit`, `delivered`.
* List parcel quotes supports `status` (`pending`, `booked`) and optional `page`.
* Retrieving a pending **export air** parcel quote refreshes its rates automatically. Booked quotes include `estimated_price` where applicable — customer payment is on **invoices**, not the quote.
* Use `direction: "export"` with `transport_mode: "air"` for multi-carrier export rates.
* Use `direction: "import"` for warehouse intake. Import quotes are created as `pending` and confirmed with `create_shipment`. The warehouse parcel is created when the agent receives the booking in Virtual Warehouse (Incoming).
* Use `transport_mode: "ocean"` with `packages[]` for container quotes. Ocean quotes return one `Ocean Freight` rate, then move to `booked` when that rate is confirmed.

For **webhooks** (`parcel.created`, `tracking.*`), see the **Webhooks** guide in the sidebar.