> 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 package that has not been converted to a shipment

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

Cancel a package that has **not** been converted to a shipment (i.e. it has no `shipment_id`).

Cancelling is a soft action: the package stays retrievable with `status` set to `cancelled` (see `cancelled_at`). Once attached to a shipment, a package can no longer be cancelled.


Reference: https://docs.trysend.com/api-reference/send-parcels-api/packages/cancel-package

## Authentication

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

## Request

### Path parameters

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

### Body (application/json)

This endpoint expects an object.

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

## Response

### 200

OK — package cancelled

- `parcel_id` (string, optional)
- `parcel_number` (string, optional)
- `customer_identifier` (string, optional)
- `status` (enum, optional)
  - Allowed values: `booked`, `warehouse`, `transit`, `delivered`, `cancelled`
- `trade_direction` (enum, optional)
  - Allowed values: `import`, `export`
- `quantity` (integer, optional)
- `declared_weight` (double, optional)
- `actual_weight` (double, optional)
- `length` (double, optional)
- `width` (double, optional)
- `height` (double, optional)
- `volume` (double, optional)
- `mode` (enum, optional)
  - Allowed values: `test`, `live`
- `hold_instruction` (enum, optional)
  - Allowed values: `hold`, `release`
- `hold_released_at` (datetime, optional, nullable)
- `warehouse_arrived_at` (datetime, optional, nullable)
- `cancelled_at` (datetime, optional, nullable) — Set when the parcel is cancelled. A parcel cannot be cancelled once it has been converted to a shipment.
- `storage_fee` (object, optional)
  - `free_days` (integer, optional) — Number of free warehouse holding days from arrival.
  - `start_date` (date, optional) — Warehouse arrival date used as the start date for storage fee calculation.
  - `last_free_day` (date, optional) — Last calendar date before storage starts accruing.
  - `chargeable_storage_days` (integer, optional) — Number of billable storage days as of today.
  - `daily_rate` (double, optional) — Storage rate per square meter per day.
  - `currency` (string, optional)
  - `storage_area_sqm` (double, optional) — Billable storage area. Uses parcel volume if present, otherwise length × width.
  - `amount_due` (double, optional) — Current storage amount due.
- `notices` (list of object, optional)
  - `token` (string, optional)
  - `uuid` (string, optional)
  - `level` (enum, optional)
    - Allowed values: `info`, `warning`, `danger`
  - `body` (string, optional)
  - `active` (boolean, optional)
  - `created_at` (datetime, optional)
  - `deactivated_at` (datetime, optional, nullable)
- `origin_country` (string, optional)
- `destination_country` (string, optional)
- `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

Package is already converted to a shipment and cannot be cancelled

- `errors` (list of string, optional)

## Examples

### Cancel a package with a comment

**Request**

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

**Response**

```json
{
  "parcel_id": "string",
  "parcel_number": "string",
  "customer_identifier": "string",
  "status": "booked",
  "trade_direction": "import",
  "quantity": 1,
  "declared_weight": 1.1,
  "actual_weight": 1.1,
  "length": 1.1,
  "width": 1.1,
  "height": 1.1,
  "volume": 1.1,
  "mode": "test",
  "hold_instruction": "hold",
  "hold_released_at": "2024-01-15T09:30:00Z",
  "warehouse_arrived_at": "2024-01-15T09:30:00Z",
  "cancelled_at": "2024-01-15T09:30:00Z",
  "storage_fee": {
    "free_days": 1,
    "start_date": "2023-01-15",
    "last_free_day": "2023-01-15",
    "chargeable_storage_days": 1,
    "daily_rate": 1.1,
    "currency": "string",
    "storage_area_sqm": 1.1,
    "amount_due": 1.1
  },
  "notices": [
    {
      "token": "string",
      "uuid": "string",
      "level": "info",
      "body": "string",
      "active": true,
      "created_at": "2024-01-15T09:30:00Z",
      "deactivated_at": "2024-01-15T09:30:00Z"
    }
  ],
  "origin_country": "string",
  "destination_country": "string",
  "created_at": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

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

url = "https://api.trysend.com/v1/packages/PKG123456789/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 package with a comment
require 'uri'
require 'net/http'

url = URI("https://api.trysend.com/v1/packages/PKG123456789/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 package without a comment

**Request**

```json
{}
```

**Response**

```json
{
  "parcel_id": "string",
  "parcel_number": "string",
  "customer_identifier": "string",
  "status": "booked",
  "trade_direction": "import",
  "quantity": 1,
  "declared_weight": 1.1,
  "actual_weight": 1.1,
  "length": 1.1,
  "width": 1.1,
  "height": 1.1,
  "volume": 1.1,
  "mode": "test",
  "hold_instruction": "hold",
  "hold_released_at": "2024-01-15T09:30:00Z",
  "warehouse_arrived_at": "2024-01-15T09:30:00Z",
  "cancelled_at": "2024-01-15T09:30:00Z",
  "storage_fee": {
    "free_days": 1,
    "start_date": "2023-01-15",
    "last_free_day": "2023-01-15",
    "chargeable_storage_days": 1,
    "daily_rate": 1.1,
    "currency": "string",
    "storage_area_sqm": 1.1,
    "amount_due": 1.1
  },
  "notices": [
    {
      "token": "string",
      "uuid": "string",
      "level": "info",
      "body": "string",
      "active": true,
      "created_at": "2024-01-15T09:30:00Z",
      "deactivated_at": "2024-01-15T09:30:00Z"
    }
  ],
  "origin_country": "string",
  "destination_country": "string",
  "created_at": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

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

url = "https://api.trysend.com/v1/packages/PKG123456789/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 package without a comment
require 'uri'
require 'net/http'

url = URI("https://api.trysend.com/v1/packages/PKG123456789/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
```