> ## Documentation Index
> Fetch the complete documentation index at: https://paperplane-justin-winter-s-projects.vercel.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Cancel an order

> Free — releases any payment hold rather than charging anything, so it requires the `cancel_token` the order creation response returned. Send it in the `X-Capability-Token` header (`X-Cancel-Token` is accepted as a legacy alias). Only possible before the letter is handed to the provider; once submitted, cancellation returns 409.



## OpenAPI

````yaml /openapi.json delete /v1/orders/{id}
openapi: 3.1.0
info:
  title: paperplane API
  version: 1.0.0
  summary: Send real physical mail from code.
  description: >-
    Upload a PDF or paste text; we print it and hand it to USPS the next
    business day. No account required — pay per letter with a Stripe link or a
    prepaid credit code, and use `sandbox: true` to exercise the whole flow for
    free.


    Every failure returns the same envelope: `status`, a stable machine-readable
    `code`, a human `reason`, and a `next` array of concrete recovery steps.


    This document is generated from the same zod schemas the server validates
    with, so it cannot describe an endpoint that does not exist.
  contact:
    name: paperplane support
    url: https://sendpaperplane.com/contact
  license:
    name: Proprietary
    identifier: LicenseRef-Proprietary
  termsOfService: https://sendpaperplane.com/terms
servers:
  - url: https://sendpaperplane.com
    description: Production
security: []
tags:
  - name: Mail
    description: Quote, send, track, and cancel letters.
  - name: Credits
    description: Prepaid balances that pay for letters without a card.
  - name: Reviews
    description: Post-delivery feedback. Identity is derived from the order, not supplied.
  - name: Addresses
    description: >-
      Typeahead and reverse geocoding. Convenience only; USPS verification is
      authoritative.
  - name: Meta
    description: Machine-readable description of this API.
paths:
  /v1/orders/{id}:
    delete:
      tags:
        - Mail
      summary: Cancel an order
      description: >-
        Free — releases any payment hold rather than charging anything, so it
        requires the `cancel_token` the order creation response returned. Send
        it in the `X-Capability-Token` header (`X-Cancel-Token` is accepted as a
        legacy alias). Only possible before the letter is handed to the
        provider; once submitted, cancellation returns 409.
      operationId: cancelOrder
      parameters:
        - name: id
          in: path
          required: true
          description: >-
            Order id, e.g. ord_1a2b3c4d5e6f7a8b (sandbox orders are
            ord_test_...).
          schema:
            type: string
        - name: X-Capability-Token
          in: header
          required: true
          description: >-
            Signed cancel token returned by POST /v1/orders for this order, as
            `capability.cancel_token`. Valid for 7 days. Both capability tokens
            carry the `ppc_` prefix — they are told apart by the action they
            were signed for, not by their prefix.
          schema:
            type: string
            pattern: ^ppc_
      responses:
        '200':
          description: The canceled order
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
              example:
                status: ok
                order:
                  id: ord_1a2b3c4d5e6f7a8b
                  status: canceled
                  sandbox: false
                  mail_class: first_class
                  page_count: 1
                  color: false
                  to:
                    name: Jordan Rivera
                    city: Springfield
                    state: IL
                    zip: '62704'
                  price_cents: 199
                  breakdown:
                    - id: first_class_letter_1_page
                      label: First-Class letter, 1 page
                      amount_cents: 199
                  tracking_number: null
                  expected_delivery_date: null
                  refusal_reason: null
                  created_at: '2026-08-23T12:00:00.000Z'
                  updated_at: '2026-08-23T12:05:00.000Z'
        '401':
          description: >-
            `invalid_key` — an Authorization header was sent and it did not
            verify. A presented credential is never silently downgraded to
            anonymous.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            `invalid_capability` — missing, malformed, or issued for a different
            order or action. Also `key_disabled` / `insufficient_scope` when an
            API key is presented.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: No order with that id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: '`too_late` — the letter has already been submitted for printing.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '410':
          description: '`expired_capability` — the cancel token is past its 7-day window.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: >-
            `key_store_unavailable` — the key could not be checked, so it is not
            honoured. Retry, or omit the header to call anonymously.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - {}
        - bearerAuth: []
components:
  schemas:
    OrderResponse:
      type: object
      properties:
        status:
          type: string
          const: ok
        order:
          $ref: '#/components/schemas/Order'
      required:
        - status
        - order
    Error:
      type: object
      properties:
        status:
          type: string
          enum:
            - failed
            - action_required
        code:
          type: string
        reason:
          type: string
        next:
          type: array
          items:
            type: string
      required:
        - status
        - code
        - reason
        - next
    Order:
      type: object
      properties:
        id:
          type: string
        status:
          type: string
          enum:
            - draft
            - pending_payment
            - screening
            - held_for_review
            - submitted
            - mailed
            - delivered
            - refused
            - canceled
            - failed
        sandbox:
          type: boolean
        mail_class:
          $ref: '#/components/schemas/MailClass'
        page_count:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        color:
          type: boolean
        to:
          type: object
          properties:
            name:
              type: string
            city:
              type: string
            state:
              type: string
            zip:
              type: string
          required:
            - name
            - city
            - state
            - zip
        price_cents:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        breakdown:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              label:
                type: string
              amount_cents:
                type: integer
                minimum: -9007199254740991
                maximum: 9007199254740991
            required:
              - id
              - label
              - amount_cents
        tracking_number:
          anyOf:
            - type: string
            - type: 'null'
        expected_delivery_date:
          anyOf:
            - type: string
            - type: 'null'
        refusal_reason:
          anyOf:
            - type: string
            - type: 'null'
        created_at:
          type: string
        updated_at:
          type: string
      required:
        - id
        - status
        - sandbox
        - mail_class
        - page_count
        - color
        - to
        - price_cents
        - breakdown
        - tracking_number
        - expected_delivery_date
        - refusal_reason
        - created_at
        - updated_at
    MailClass:
      type: string
      enum:
        - first_class
        - certified
        - certified_err
        - priority
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Optional developer API key: `Authorization: Bearer pp_live_…` (or
        `pp_test_…` for a sandbox-only key). Omitting it is a supported way to
        call every route. A key that is sent and does not verify is refused with
        401 rather than treated as anonymous, so a typo fails loudly instead of
        quietly losing the restriction you meant to apply. Enabled per
        deployment via `SCOPED_API_KEYS`.

````