---
title: "Cancel a preorder"
method: POST
path: "/preorders/{preorder}/cancel"
tags: ["Preorders"]
---

# Cancel a preorder

`POST /preorders/{preorder}/cancel`

## Request

- Base URL: `https://api.ekho.com`
- URL: `https://api.ekho.com/preorders/{preorder}/cancel`
- Auth: HTTP bearer

Refunds the reservation fee in full, cancels the preorder, and returns the canceled preorder. Any checkout cart opened from the preorder is disabled by the same write. The preorder is marked canceled only once the refund has landed, so a 200 means the money is back and a failure leaves the preorder as it stands. Canceling is safe to repeat: a payment already refunded is skipped and the cancelation date does not move. A preorder that has converted to an order cannot be canceled here. The buyer is never expanded on this response.

## Path parameters

- `preorder` string, required

## Response `200`

The preorder as it stands after the cancelation.

- object
  - `data` Preorder, required
    - `id` string, required
    - `created_at` integer, required: Epoch ms the reservation fee was paid.
    - `canceled_at` integer, nullable, required
    - `status` 'pending_invitation' | 'awaiting_checkout' | 'idle' | 'converted' | 'canceled', required
    - `catalog_vehicle` CatalogVehicle, required
      - `manufacturer_id` string, nullable, required: Catalog id of the manufacturer that makes the vehicle, and the namespace the other ids are unique beneath.
      - `model_id` string, nullable, required: Catalog id of the model the trim belongs to, carrying the make, model, and year. Null while the vehicle sits outside the catalog.
      - `variant_id` string, nullable, required: Catalog id of the trim. Pass it with `style_id` to name this vehicle on `POST /carts/build-to-order`. Null while the vehicle sits outside the catalog.
      - `style_id` string, nullable, required: Catalog id of the colour style. Pass it with `variant_id` to name this vehicle on `POST /carts/build-to-order`. Null while the vehicle sits outside the catalog.
      - `name` string, required
      - `img_url` string, nullable, required
      - `base_price` number, required: Base price USD of the build, before specs and PG&A.
      - `specs` Spec[], required: The build-defining items configured onto this vehicle.
        - `name` string, required
        - `category` string, nullable, required
        - `sku` string, nullable, required
        - `price` number, required: Price USD as sold. 0 for items included in the base price.
        - `description` string, nullable, required
        - `img_url` string, nullable, required
    - `deposit` number, required: Reservation fee paid, USD.
    - `converted_order_id` string, nullable, required
    - `checkout_cart_id` string, nullable, required
    - `converted_cart_id` string, nullable, required
    - `assigned_account_id` string, nullable, required
    - `buyer` PreorderBuyer: Buyer with PII. Present only when requested via `?expand[]=buyer`.
      - `id` string, required: Buyer id, the same handle on every resource.
      - `full_name` string, required
      - `email` string, nullable, required: Buyer email; null when the buyer record is unavailable.
      - `phone` string, nullable, required: Buyer phone; null when the buyer record is unavailable.
      - `address` BuyerAddress, nullable, required: Buyer address; null when none is on file.
        - `line1` string, required
        - `line2` string, nullable, required
        - `city` string, required
        - `state` string, required: Two-letter state code.
        - `zip` string, required
        - `country` string, nullable, required: ISO 3166-1 alpha-2; null implies US.
      - `consents` Consent[], required: Consent events for this buyer, oldest first. Read the newest row per channel and purpose. An absent pair means do not send, except email + transactional, which needs no consent.
        - `channel` 'sms' | 'email' | 'voice', required
        - `purpose` 'transactional' | 'marketing', required
        - `status` 'granted' | 'revoked', required
        - `occurred_at` integer, required: Epoch ms the buyer granted or withdrew.
        - `disclosure_text` string, nullable, required: The disclosure verbatim, as rendered. Null on a revocation.
        - `source_url` string, nullable, required: Page it was captured on. Null on a revocation.
    - `pga` Pga[], required: Parts, garments, and accessories (PG&A) sold with the build.
      - `type` 'part' | 'garment' | 'accessory', required
      - `name` string, required
      - `category` string, nullable, required
      - `sku` string, nullable, required
      - `price` number, required: Unit price USD as sold. 0 for included items.
      - `quantity` integer, required
      - `description` string, nullable, required
      - `img_url` string, nullable, required
    - `metadata` object, required: Free-form metadata carried on the preorder, including whatever was attached at cart creation. Published exactly as written, so objects and arrays round-trip with their structure intact. Always present, empty when unset.

## Other responses

- `400`: The request was malformed or failed validation. `errors` itemizes every field at fault, so one response names them all; the fields in the example stand in for this request's own.
- `401`: Authentication is missing or invalid.
- `403`: The token lacks `preorders:write`.
- `404`: No preorder matches that id.
- `409`: The preorder has converted to an order and cannot be canceled.
- `429`: The rate limit has been exceeded.
- `500`: An unexpected error occurred.

## Changes

- **2026-10-20** `819b111dc3bc`: 1 breaking
  - the `data/buyer/consents/items/occurred_at` response's property type changed from `string` to `integer` for status `200`
- **2026-10-19** `87f98453866f`: 1 info
  - added the required property `data/buyer/consents` to the response with the `200` status
- **2026-09-18** `78c545d96a34`: 21 warning
  - added the new `external_id_in_use` enum value to the `code` response property for the response status `400`
  - added the new `external_id_in_use` enum value to the `code` response property for the response status `401`
  - added the new `external_id_in_use` enum value to the `code` response property for the response status `403`
  - added the new `external_id_in_use` enum value to the `code` response property for the response status `404`
  - …17 more

[Operation history](https://skmtc.dev/ekho/apis/ekho-api/changes/preorders/:preorder/cancel/post.md)

---

[API](https://skmtc.dev/ekho/apis/ekho-api.md) · [All operations](https://skmtc.dev/ekho/apis/ekho-api/llms.txt) · [OpenAPI document](https://skmtc.dev/ekho/apis/ekho-api/revisions/efe485119dd7?raw)
