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

# Cancel a pending parcel quote

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

Cancel a parcel quote that has **not** been converted to a shipment. Only `pending` quotes can be cancelled.

Cancelling a quote is a soft action: the quote stays retrievable with `status` set to `cancelled` (see `cancelled_at`, `closed_reason`, and `comment`). Once cancelled it cannot be purchased (`create_shipment` will reject it).


Reference: https://docs.trysend.com/api-reference/send-parcels-api/parcel-quotes/cancel-parcel-quote

## Authentication

- `X-Api-Key` header (required) — API Key authentication via header

## Request

### Path parameters

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

### Body (application/json)

This endpoint expects an object.

- `comment` (string, optional) — Optional free-text reason for the cancellation.

## Response

### 200

OK — quote cancelled

- `parcel_quote_id` (string, optional)
- `status` (enum, optional)
  - Allowed values: `pending`, `booked`, `cancelled`
- `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`.
- `cancelled_at` (datetime, optional, nullable) — When the quote was cancelled. Null while not `cancelled`.
- `closed_reason` (string, optional, nullable) — Reason the quote was cancelled.
- `comment` (string, optional, nullable) — Optional free-text note attached when the quote was cancelled.
- `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)

## Errors

### 401 Unauthorized Error

Missing or invalid API key

### 404 Not Found Error

Not found

- `error` (string, optional)

### 422 Unprocessable Entity Error

Quote is already booked and cannot be cancelled

- `object or object`
  - ErrorsList
    - `errors` (list of string, optional)
  - object
    - `errors` (list of string, optional)
    - `code` (string, optional)

## Examples

### Cancel a quote with a comment

**Request**

```json
{
  "comment": "Customer no longer needs this shipment"
}
```

**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",
  "cancelled_at": "2024-01-15T09:30:00Z",
  "closed_reason": "string",
  "comment": "string",
  "estimated_price": 6246625,
  "created_at": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

```python Cancel a quote with a comment
import requests

url = "https://api.trysend.com/v1/parcel_quotes/pq_abc123xyz/cancel"

payload = { "comment": "Customer no longer needs this shipment" }
headers = {
    "X-Api-Key": "<apiKey>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

```ruby Cancel a quote with a comment
require 'uri'
require 'net/http'

url = URI("https://api.trysend.com/v1/parcel_quotes/pq_abc123xyz/cancel")

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  \"comment\": \"Customer no longer needs this shipment\"\n}"

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

### Cancel a quote without a comment

**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",
  "cancelled_at": "2024-01-15T09:30:00Z",
  "closed_reason": "string",
  "comment": "string",
  "estimated_price": 6246625,
  "created_at": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

```python Cancel a quote without a comment
import requests

url = "https://api.trysend.com/v1/parcel_quotes/pq_abc123xyz/cancel"

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

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

print(response.json())
```

```ruby Cancel a quote without a comment
require 'uri'
require 'net/http'

url = URI("https://api.trysend.com/v1/parcel_quotes/pq_abc123xyz/cancel")

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