> 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.

# Confirm pending quote (create shipment)

POST https://api.trysend.com/v1/packages/{id}/create_shipment
Content-Type: application/json

Confirm a pending parcel quote. Pass a `rate_id` from the quote's `rates[]` when rates are present.

- **Export air** — buys the selected carrier rate and returns `tracking_code` and `label_url`.
- **Import air** — confirms the SendHQ warehouse-intake quote and moves it to `booked`; no `rate_id` or carrier label is required.
- **Ocean** — confirms the single SendHQ `Ocean Freight` estimate and moves the quote to `booked`; no carrier label is created.

Returns `QUOTE_RATE_OUTDATED` when the `rate_id` is older than one hour — `GET` the quote to refresh rates first.


Reference: https://docs.trysend.com/api-reference/send-parcels-api/packages/create-shipment

## Authentication

- `X-Api-Key` header (required)

## Request

### Path parameters

- `id` (string, required) — Parcel quote token

### Body (application/json)

- `rate_id` (string, optional) — Rate ID from the quote's rates array. Required when the quote returned rates.

## Response

### 200

OK — shipment created

- `parcel_quote_id` (string, optional)
- `status` (enum, optional)
  - Allowed values: `pending`, `booked`
- `source` (string, optional)
- `direction` (string, optional)
- `reference` (string, optional)
- `rates` (list of object, optional)
  - `id` (string, optional)
  - `carrier` (string, optional)
  - `service` (string, optional)
  - `rate` (string, optional)
  - `currency` (string, optional)
  - `estimated_delivery_days` (integer, optional, nullable) — Estimated transit days. Ocean rates return 11; typical 10–12, worst case up to 14.
  - `estimated_delivery_date` (date, optional, nullable) — Estimated delivery date (ISO date). Ocean uses today + 11 calendar days.
- `sender` (object, optional)
  - `name` (string, optional)
  - `email` (string, optional)
  - `phone` (string, optional)
  - `address` (object, optional)
    - `street` (string, optional)
    - `city` (string, optional)
    - `state` (string, optional)
    - `postal_code` (string, optional)
    - `country` (string, optional) — ISO-2/ISO-3 country code or country name. For example, `US`, `USA`, and `United States` are accepted.
- `recipient` (object, optional)
  - `name` (string, optional)
  - `email` (string, optional)
  - `phone` (string, optional)
  - `address` (object, optional)
    - `street` (string, optional)
    - `city` (string, optional)
    - `state` (string, optional)
    - `postal_code` (string, optional)
    - `country` (string, optional) — ISO-2/ISO-3 country code or country name. For example, `US`, `USA`, and `United States` are accepted.
- `package` (object, optional) — Air weight/dimensions, or ocean `packages[]` nested under `package` in responses.
  - `weight` (double, optional)
  - `length` (double, optional)
  - `width` (double, optional)
  - `height` (double, optional)
  - `item_description` (string, optional)
- `cargo_volume` (string, optional) — Human-readable cargo summary, e.g. `2 x 40'` (ocean) or `5 kg` (air).
- `origin_details` (object, optional)
- `dest_details` (object, optional)
- `parcel_details` (object, optional)
- `tracking_code` (string, optional, nullable)
- `label_url` (string, optional, nullable)
- `selected_rate` (object, optional, nullable)
- `tracker_id` (string, optional, nullable)
- `purchased_at` (datetime, optional, nullable) — Legacy booking timestamp when status is `booked`. Same moment as `booked_at`. Not payment confirmation for ocean/import intake quotes.
- `booked_at` (datetime, optional, nullable) — When the quote became `booked`. Null while `pending`.
- `estimated_price` (double, optional, nullable) — NGN total from `selected_rate.rate`. For ocean/import intake, provisional until warehouse receive; customer payment is invoiced separately.
- `created_at` (datetime, optional)

## Examples

### Confirm a quote with a selected rate

**Request**

```json
{
  "rate_id": "rate_123abc"
}
```

**Response**

```json
{
  "parcel_quote_id": "string",
  "status": "pending",
  "source": "string",
  "direction": "string",
  "reference": "string",
  "rates": [
    {
      "id": "string",
      "carrier": "string",
      "service": "string",
      "rate": "string",
      "currency": "string",
      "estimated_delivery_days": 1,
      "estimated_delivery_date": "2023-01-15"
    }
  ],
  "sender": {
    "name": "John Sender",
    "email": "sender@example.com",
    "phone": "+1234567890",
    "address": {
      "street": "123 Main St",
      "city": "New York",
      "state": "NY",
      "postal_code": "10001",
      "country": "US"
    }
  },
  "recipient": {
    "name": "John Sender",
    "email": "sender@example.com",
    "phone": "+1234567890",
    "address": {
      "street": "123 Main St",
      "city": "New York",
      "state": "NY",
      "postal_code": "10001",
      "country": "US"
    }
  },
  "package": {
    "weight": 5,
    "length": 10,
    "width": 8,
    "height": 6,
    "item_description": "Electronics"
  },
  "cargo_volume": "1 x 40'",
  "origin_details": {},
  "dest_details": {},
  "parcel_details": {},
  "tracking_code": "string",
  "label_url": "string",
  "selected_rate": {},
  "tracker_id": "string",
  "purchased_at": "2024-01-15T09:30:00Z",
  "booked_at": "2024-01-15T09:30:00Z",
  "estimated_price": 6246625,
  "created_at": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

```python Confirm a quote with a selected rate
import requests

url = "https://api.trysend.com/v1/packages/pq_abc123xyz/create_shipment"

payload = { "rate_id": "rate_123abc" }
headers = {
    "X-Api-Key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```ruby Confirm a quote with a selected rate
require 'uri'
require 'net/http'

url = URI("https://api.trysend.com/v1/packages/pq_abc123xyz/create_shipment")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"rate_id\": \"rate_123abc\"\n}"

response = http.request(request)
puts response.read_body
```

### Confirm import air without a rate

**Request**

```json
{}
```

**Response**

```json
{
  "parcel_quote_id": "string",
  "status": "pending",
  "source": "string",
  "direction": "string",
  "reference": "string",
  "rates": [
    {
      "id": "string",
      "carrier": "string",
      "service": "string",
      "rate": "string",
      "currency": "string",
      "estimated_delivery_days": 1,
      "estimated_delivery_date": "2023-01-15"
    }
  ],
  "sender": {
    "name": "John Sender",
    "email": "sender@example.com",
    "phone": "+1234567890",
    "address": {
      "street": "123 Main St",
      "city": "New York",
      "state": "NY",
      "postal_code": "10001",
      "country": "US"
    }
  },
  "recipient": {
    "name": "John Sender",
    "email": "sender@example.com",
    "phone": "+1234567890",
    "address": {
      "street": "123 Main St",
      "city": "New York",
      "state": "NY",
      "postal_code": "10001",
      "country": "US"
    }
  },
  "package": {
    "weight": 5,
    "length": 10,
    "width": 8,
    "height": 6,
    "item_description": "Electronics"
  },
  "cargo_volume": "1 x 40'",
  "origin_details": {},
  "dest_details": {},
  "parcel_details": {},
  "tracking_code": "string",
  "label_url": "string",
  "selected_rate": {},
  "tracker_id": "string",
  "purchased_at": "2024-01-15T09:30:00Z",
  "booked_at": "2024-01-15T09:30:00Z",
  "estimated_price": 6246625,
  "created_at": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

```python Confirm import air without a rate
import requests

url = "https://api.trysend.com/v1/packages/pq_abc123xyz/create_shipment"

payload = {}
headers = {
    "X-Api-Key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```ruby Confirm import air without a rate
require 'uri'
require 'net/http'

url = URI("https://api.trysend.com/v1/packages/pq_abc123xyz/create_shipment")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{}"

response = http.request(request)
puts response.read_body
```