openapi: 3.1.0
info:
  title: Automations API
  description: 'Buy the right label in one call.


    Shipping a parcel through the Shippo API takes four steps today: create a shipment,
    fetch rates, compare them against your own logic, then buy the label. Automations
    collapses that into one request. You send the shipment, Shippo applies your rules,
    selects the rate, and buys the label.


    ## What the rules are


    In this beta, every account is provisioned with exactly one rule, named `default`,
    which selects the lowest-cost eligible rate for the shipment. A few USPS service
    levels whose eligibility Automations can''t check, such as Media Mail, are never
    selected; see [Service levels the rule never selects](https://docs.goshippo.com/automations/automations#service-levels-the-rule-never-selects).
    The rule is created for you the first time you call the API. There is nothing
    to configure, and there is no endpoint for authoring or editing rules yet. Customer-defined
    rules are planned for a later release.


    ## Decision transparency


    Every request keeps a decision record. `GET /automations/labels/{request_id}/decision`
    returns the rule that matched, the rate selected, the facts the engine evaluated,
    and the full rule trace. Use it to answer "why this carrier, why this price" without
    building and instrumenting your own rate-comparison logic.


    ## Beta status


    These endpoints are in beta. Request and response shapes may change without the
    notice period that applies to generally available Shippo endpoints, and they are
    not yet covered by the `SHIPPO-API-VERSION` header. Breaking changes are announced
    to enrolled accounts before they ship. Pin nothing in production that you cannot
    redeploy.'
  contact:
    name: Shippo API Support
    url: https://support.goshippo.com/
  version: beta
servers:
- url: https://api.goshippo.com
  description: Shippo API
paths:
  /automations/labels:
    post:
      tags:
      - Automations
      summary: Buy a label using your automation rules
      description: 'Purchases a shipping label. **This spends money.** A successful
        request charges your Shippo account for the selected rate; it cannot be undone
        through this API (refunds go through the [Refunds API](https://docs.goshippo.com/api-reference/refunds/create-a-refund)).


        Send `dry_run: true` to see which rate the rules would select, with no purchase
        and no charge. Automated callers should dry-run an unfamiliar shipment shape
        before running it live.


        The request body is the standard Shippo `POST /shipments` create body, plus
        `dry_run`; any field that endpoint accepts is passed through unchanged.


        Responds `202` with a `request_id` and a `poll_url`. Work continues asynchronously
        — poll `GET /automations/labels/{request_id}` until `status` reaches a terminal
        state (`purchased`, `dry_run_completed`, `no_match`, or `failed`).


        The `Idempotency-Key` header is required. Repeating a **live** request with
        the same key returns a pointer to the original request instead of creating
        a duplicate; dry runs are never deduplicated (each `dry_run` request starts
        a new evaluation).'
      operationId: createAutomationsLabel
      parameters:
      - name: Idempotency-Key
        in: header
        required: true
        schema:
          type: string
          minLength: 1
          maxLength: 255
          title: Idempotency-Key
        description: 'Required. A client-generated key that makes retries safe: repeating
          a request with the same key returns the original result instead of creating
          a duplicate.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AutomationsLabelRequest'
            examples:
              inline:
                summary: Inline addresses + parcel
                value:
                  address_from:
                    name: Acme
                    street1: 215 Clayton St
                    city: San Francisco
                    state: CA
                    zip: '94117'
                    country: US
                  address_to:
                    name: Casey
                    street1: 965 Mission St
                    city: San Francisco
                    state: CA
                    zip: '94103'
                    country: US
                  parcels:
                  - length: '10'
                    width: '8'
                    height: '4'
                    distance_unit: in
                    weight: '2'
                    mass_unit: lb
              dry_run:
                summary: Dry run (evaluate, do not purchase)
                value:
                  address_from: d799c2679e644279b59fe661ac8fa489
                  address_to: 3f8a1c2b4d5e6f708192a3b4c5d6e7f8
                  parcels:
                  - a1b2c3d4e5f60718293a4b5c6d7e8f90
                  dry_run: true
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcceptedResponse'
        '401':
          description: Missing or invalid API token. The `detail` message depends
            on the problem; the example is the response when no token is sent.
          content:
            application/json:
              example:
                detail: Authentication credentials were not provided.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '403':
          description: This account does not have access to Automations.
          content:
            application/json:
              example:
                detail: Automations is not available for this account.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '503':
          description: Automations is temporarily unavailable. Retry later.
          content:
            application/json:
              example:
                detail: Automations is temporarily unavailable.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    get:
      tags:
      - Automations
      summary: List label-purchase requests
      description: 'Lists your label-purchase requests, newest first. Read-only. Returns
        a page of summaries plus a `next` link (an opaque cursor); `next` is `null`
        on the last page.


        The `shipment_id`, `tracking_number`, `status`, and `dry_run` filters are
        AND-combined, and are preserved across pages by the `next` link.'
      operationId: listAutomationsLabels
      parameters:
      - name: cursor
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Cursor
        description: Opaque next-page token; use the `next` link from a prior response
          verbatim.
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 25
          title: Limit
        description: Page size, 1–100 (default 25).
      - name: shipment_id
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Shipment Id
        description: Filter to requests with this shipment_id.
      - name: tracking_number
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Tracking Number
        description: Filter to requests with this tracking number.
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - $ref: '#/components/schemas/AutomationsLabelStatus'
          - type: 'null'
          title: Status
        description: 'Filter by status: processing, purchased, dry_run_completed,
          no_match, or failed.'
      - name: dry_run
        in: query
        required: false
        schema:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Dry Run
        description: Filter to dry-run (true) or live (false) requests.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutomationsLabelListResponse'
        '401':
          description: Missing or invalid API token. The `detail` message depends
            on the problem; the example is the response when no token is sent.
          content:
            application/json:
              example:
                detail: Authentication credentials were not provided.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '403':
          description: This account does not have access to Automations.
          content:
            application/json:
              example:
                detail: Automations is not available for this account.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '503':
          description: Automations is temporarily unavailable. Retry later.
          content:
            application/json:
              example:
                detail: Automations is temporarily unavailable.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /automations/labels/{request_id}:
    get:
      tags:
      - Automations
      summary: Get request status
      description: 'Returns the current status and outcome of a label-purchase request.
        Read-only and safe to call repeatedly.


        Poll while `status` is `processing`. Terminal outcomes are `purchased`, `dry_run_completed`,
        `no_match`, and `failed`. The `dry_run` field identifies dry runs, which can
        also end in `no_match` or `failed`.


        A `no_match` outcome includes `reason.code` and `reason.message`: rules and
        fallback selected nothing (`no_match`), every returned rate was excluded from
        automatic selection (`all_rates_excluded`), or no rates were returned for
        the shipment (`no_rates_returned`). Reason codes may be added; tolerate unknown
        codes. `purchased` and `dry_run_completed` need no reason.


        A successful poll returns HTTP 200 for every outcome. Only `failed` includes
        `error`; branch on its code and tolerate additional codes. A failed automation
        may have an unconfirmed purchase: check the account or transaction before
        retrying when instructed by the error.


        Returns `404` for a request id that does not exist or does not belong to your
        account.'
      operationId: getAutomationsLabel
      parameters:
      - name: request_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Request Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                oneOf:
                - $ref: '#/components/schemas/ProcessingStatus'
                - $ref: '#/components/schemas/DryRunCompletedStatus'
                - $ref: '#/components/schemas/PurchasedStatus'
                - $ref: '#/components/schemas/NoMatchStatus'
                - $ref: '#/components/schemas/FailedStatus'
                discriminator:
                  propertyName: status
                  mapping:
                    processing: '#/components/schemas/ProcessingStatus'
                    dry_run_completed: '#/components/schemas/DryRunCompletedStatus'
                    purchased: '#/components/schemas/PurchasedStatus'
                    no_match: '#/components/schemas/NoMatchStatus'
                    failed: '#/components/schemas/FailedStatus'
                title: Response 200 Getautomationslabel
        '401':
          description: Missing or invalid API token. The `detail` message depends
            on the problem; the example is the response when no token is sent.
          content:
            application/json:
              example:
                detail: Authentication credentials were not provided.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '403':
          description: This account does not have access to Automations.
          content:
            application/json:
              example:
                detail: Automations is not available for this account.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '503':
          description: Automations is temporarily unavailable. Retry later.
          content:
            application/json:
              example:
                detail: Automations is temporarily unavailable.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '404':
          description: No automation request with that id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /automations/labels/{request_id}/decision:
    get:
      tags:
      - Automations
      summary: Get the decision behind a selected rate
      description: 'Returns the rule-evaluation decision for a request: the rule that
        matched, the rate selected, the facts the engine evaluated, and the full rule
        trace. Read-only.


        This is the answer to "why this carrier, why this price" — the audit record
        for the decision; it does not change once written.


        In this beta the matched rule is always `default`, the single rule provisioned
        for your account. `matched_priority` and `fallback_triggered` describe ordering
        and fallback behavior that become meaningful when customer-defined rules ship.


        Available once evaluation has written a decision, including while a purchase
        is still `processing`. Outcomes reached before evaluation have no decision
        and return `409`, and `404` for a request id that does not exist or does not
        belong to your account.'
      operationId: getAutomationsLabelDecision
      parameters:
      - name: request_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Request Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DecisionResponse'
        '401':
          description: Missing or invalid API token. The `detail` message depends
            on the problem; the example is the response when no token is sent.
          content:
            application/json:
              example:
                detail: Authentication credentials were not provided.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '403':
          description: This account does not have access to Automations.
          content:
            application/json:
              example:
                detail: Automations is not available for this account.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '503':
          description: Automations is temporarily unavailable. Retry later.
          content:
            application/json:
              example:
                detail: Automations is temporarily unavailable.
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '404':
          description: No automation request with that id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '409':
          description: Evaluation has not completed; no decision to return yet.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DetailResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    AcceptedResponse:
      properties:
        request_id:
          type: string
          format: uuid
          title: Request Id
        status:
          $ref: '#/components/schemas/AutomationsLabelStatus'
          description: Current status of the request.
        poll_url:
          type: string
          title: Poll Url
      type: object
      required:
      - request_id
      - status
      - poll_url
      title: AcceptedResponse
      description: 'Returned by `POST /automations/labels`: a pointer to the accepted
        request. Repeating a live request with the same `Idempotency-Key` returns
        the original request''s pointer, with `status` showing that request''s current
        outcome.'
      example:
        poll_url: /automations/labels/b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        status: processing
    AddressCreate:
      properties:
        name:
          type: string
          minLength: 1
          title: Name
          description: Recipient/sender full name.
        street1:
          type: string
          minLength: 1
          title: Street1
          description: Primary street line.
        city:
          type: string
          minLength: 1
          title: City
          description: City / locality.
        state:
          anyOf:
          - type: string
            minLength: 1
          - type: 'null'
          title: State
          description: State / province. Required for some countries (e.g. US, CA).
        zip:
          anyOf:
          - type: string
            minLength: 1
          - type: 'null'
          title: Zip
          description: Postal / ZIP code. Required for some countries.
        country:
          type: string
          minLength: 1
          title: Country
          description: ISO 3166-1 alpha-2 country code (e.g. "US").
      additionalProperties: true
      type: object
      required:
      - name
      - street1
      - city
      - country
      title: AddressCreate
      description: An inline Shippo address. The fields every shippable address needs
        are required; `state` and `zip` are optional because only some countries require
        them. To reuse an address you already created, pass its `object_id` string
        instead. Any other valid Shippo address field (for example `company`, `phone`,
        `email`, `validate`) is accepted and passed through unchanged.
    AutomationsLabelListResponse:
      properties:
        results:
          items:
            $ref: '#/components/schemas/AutomationsLabelSummary'
          type: array
          title: Results
        next:
          anyOf:
          - type: string
          - type: 'null'
          title: Next
      type: object
      required:
      - results
      - next
      title: AutomationsLabelListResponse
      description: A page of request summaries, newest first. `next` links to the
        following page with your filters and page size already applied; it is `null`
        on the last page.
    AutomationsLabelRequest:
      properties:
        address_from:
          anyOf:
          - $ref: '#/components/schemas/AddressCreate'
          - type: string
            description: An existing Shippo address object_id (typically a 32-character
              hex string, e.g. "d799c2679e644279b59fe661ac8fa489"). https://docs.goshippo.com/api-reference/shipments/create-a-new-shipment
          title: Address From
          description: 'Origin: an inline address object or an existing address id.
            https://docs.goshippo.com/api-reference/shipments/create-a-new-shipment#body-address-from-one-of-0'
        address_to:
          anyOf:
          - $ref: '#/components/schemas/AddressCreate'
          - type: string
            description: An existing Shippo address object_id (typically a 32-character
              hex string, e.g. "d799c2679e644279b59fe661ac8fa489"). https://docs.goshippo.com/api-reference/shipments/create-a-new-shipment
          title: Address To
          description: 'Destination: an inline address object or an existing address
            id. https://docs.goshippo.com/api-reference/shipments/create-a-new-shipment#body-address-to-one-of-0'
        parcels:
          anyOf:
          - $ref: '#/components/schemas/ParcelCreate'
          - items:
              anyOf:
              - $ref: '#/components/schemas/ParcelCreate'
              - type: string
                description: An existing Shippo parcel object_id (typically a 32-character
                  hex string, e.g. "a1b2c3d4e5f60718293a4b5c6d7e8f90"). https://docs.goshippo.com/api-reference/shipments/create-a-new-shipment#body-parcels
            type: array
          title: Parcels
          description: One parcel object, a list of parcel objects, or a list of parcel
            ids. https://docs.goshippo.com/api-reference/shipments/create-a-new-shipment#body-parcels
        dry_run:
          type: boolean
          title: Dry Run
          description: When true, evaluate rules and select a rate but do NOT purchase
            a label. Requires a genuine JSON boolean (no coercion).
          default: false
      additionalProperties: true
      type: object
      required:
      - address_from
      - address_to
      - parcels
      title: AutomationsLabelRequest
      description: 'The body for `POST /automations/labels`: the Shippo create-shipment
        body plus `dry_run`. Any field that endpoint accepts is passed through unchanged,
        so the shipment Shippo rates and buys is exactly the one you sent. Only the
        address and parcel fields are described here; for the full field list, see
        [Create a new shipment](https://docs.goshippo.com/api-reference/shipments/create-a-new-shipment).'
    AutomationsLabelStatus:
      type: string
      enum:
      - processing
      - purchased
      - dry_run_completed
      - no_match
      - failed
      title: AutomationsLabelStatus
    AutomationsLabelSummary:
      properties:
        request_id:
          type: string
          format: uuid
          title: Request Id
        status:
          $ref: '#/components/schemas/AutomationsLabelStatus'
          description: Current status of the request.
        shipment_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Shipment Id
        tracking_number:
          anyOf:
          - type: string
          - type: 'null'
          title: Tracking Number
        dry_run:
          type: boolean
          title: Dry Run
          description: Whether this request evaluates selection without purchasing
            a label.
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - request_id
      - status
      - shipment_id
      - tracking_number
      - dry_run
      - created_at
      title: AutomationsLabelSummary
      description: One request in the `GET /automations/labels` list. Every summary
        has the same fields whatever its status; a field with no value yet is `null`
        rather than omitted. For the full outcome, get the request by `request_id`.
    DecisionBlock:
      properties:
        decision_log_id:
          type: string
          format: uuid
          title: Decision Log Id
        auto_provisioned:
          type: boolean
          title: Auto Provisioned
        estimate_available:
          type: boolean
          title: Estimate Available
        matched_rule_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Matched Rule Name
        matched_priority:
          anyOf:
          - type: integer
          - type: 'null'
          title: Matched Priority
        fallback_triggered:
          type: boolean
          title: Fallback Triggered
        selected_rate:
          anyOf:
          - $ref: '#/components/schemas/SelectedRate'
          - type: 'null'
        facts_input:
          additionalProperties: true
          type: object
          title: Facts Input
        ruleset_snapshot:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Ruleset Snapshot
        rule_trace:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Rule Trace
      type: object
      required:
      - decision_log_id
      - auto_provisioned
      - estimate_available
      - fallback_triggered
      - facts_input
      - rule_trace
      title: DecisionBlock
      description: 'The record of one completed rule evaluation: the rule that matched,
        the rate selected, the facts evaluated, and the full rule trace. It is written
        once and never changes. `estimate_available` is always `false` in this beta.'
    DecisionResponse:
      properties:
        request_id:
          type: string
          format: uuid
          title: Request Id
        test:
          type: boolean
          title: Test
          description: Whether this request was created in test mode.
        status:
          $ref: '#/components/schemas/AutomationsLabelStatus'
          description: Current status of the request.
        dry_run:
          type: boolean
          title: Dry Run
          description: Whether this request evaluates selection without purchasing
            a label.
        shipment_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Shipment Id
        transaction_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Transaction Id
        tracking_number:
          anyOf:
          - type: string
          - type: 'null'
          title: Tracking Number
        label_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Label Url
        created_at:
          type: string
          format: date-time
          title: Created At
        evaluated_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Evaluated At
        label_processed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Label Processed At
        decision:
          $ref: '#/components/schemas/DecisionBlock'
      type: object
      required:
      - request_id
      - test
      - status
      - dry_run
      - created_at
      - decision
      title: DecisionResponse
      description: 'Returned by `GET /automations/labels/{request_id}/decision`: the
        request''s status and identifiers plus its full decision record. Available
        once rule evaluation has completed.'
      examples:
      - request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        test: false
        status: purchased
        dry_run: false
        shipment_id: 5e40ead7cffe4cc1ad45108696162e42
        transaction_id: 9b2d4f6a8c0e4a1b3d5f7a9c1e3b5d7f
        tracking_number: '9400111899223197428490'
        label_url: https://shippo-delivery.s3.amazonaws.com/2f8b6d1e4a9c4f3b8e7d5a1c6b9e0f24.pdf
        created_at: '2026-09-03T18:04:10Z'
        evaluated_at: '2026-09-03T18:04:12Z'
        label_processed_at: '2026-09-03T18:04:20Z'
        decision:
          decision_log_id: c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f
          auto_provisioned: true
          estimate_available: false
          matched_rule_name: default
          matched_priority: 1
          fallback_triggered: false
          selected_rate:
            rate_id: c4e8a2f6d0b94c17a3e5f7b9d1c3e5a7
            carrier: USPS
            service_level: usps_priority
            amount: '7.35'
          facts_input:
            planned_ship_date: null
          ruleset_snapshot:
            rule_set_id: d4e5f6a7-b8c9-4d0e-9f1a-2b3c4d5e6f70
            fallback:
              strategy: min_field
              field: cost
            rules:
            - priority: 1
              rule_id: e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a81
              name: default
              version: 1
              condition_groups: []
              action:
                strategy: min_field
                field: cost
          rule_trace:
          - priority: 1
            rule_id: e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a81
            rule_name: default
            rule_version: 1
            matched: true
            short_circuited: false
            condition_results: []
            selection:
              strategy: min_field
              field: cost
              winner_id: c4e8a2f6d0b94c17a3e5f7b9d1c3e5a7
              values_considered:
              - rate_id: c4e8a2f6d0b94c17a3e5f7b9d1c3e5a7
                value: '7.35'
              - rate_id: 7a1c3e5b9d2f4a6c8e0b1d3f5a7c9e2b
                value: '9.85'
              tiebreaker_applied: false
              tiebreaker_resolved_by: null
              tied_candidates: []
    DetailResponse:
      properties:
        detail:
          type: string
          title: Detail
          description: Human-readable explanation of why the request could not be
            served.
      type: object
      required:
      - detail
      title: DetailResponse
      description: An error with a single human-readable `detail` message.
    DryRunCompletedStatus:
      properties:
        request_id:
          type: string
          format: uuid
          title: Request Id
        test:
          type: boolean
          title: Test
          description: Whether this request was created in test mode.
        status:
          type: string
          const: dry_run_completed
          title: Status
          description: A rate was selected; no purchase was attempted.
        dry_run:
          type: boolean
          title: Dry Run
          description: True for a completed dry run; no label is purchased.
        shipment_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Shipment Id
        decision_log_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Decision Log Id
        selected_rate:
          anyOf:
          - $ref: '#/components/schemas/SelectedRate'
          - type: 'null'
        matched_rule_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Matched Rule Name
        matched_priority:
          anyOf:
          - type: integer
          - type: 'null'
          title: Matched Priority
        fallback_triggered:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Fallback Triggered
        evaluated_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Evaluated At
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - request_id
      - test
      - status
      - dry_run
      - created_at
      title: DryRunCompletedStatus
      examples:
      - request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        test: false
        status: dry_run_completed
        dry_run: true
        decision_log_id: c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f
        selected_rate:
          rate_id: c4e8a2f6d0b94c17a3e5f7b9d1c3e5a7
          carrier: USPS
          service_level: usps_priority
          amount: '7.35'
        matched_rule_name: default
        matched_priority: 1
        fallback_triggered: false
        evaluated_at: '2026-09-03T18:04:12Z'
        created_at: '2026-09-03T18:04:10Z'
    ErrorBody:
      properties:
        code:
          type: string
          title: Code
          description: Stable error code. Integrations must tolerate additional codes.
        message:
          type: string
          minLength: 1
          title: Message
          description: Customer-safe explanation. Wording may change.
      type: object
      required:
      - code
      - message
      title: ErrorBody
    FailedStatus:
      properties:
        request_id:
          type: string
          format: uuid
          title: Request Id
        test:
          type: boolean
          title: Test
          description: Whether this request was created in test mode.
        status:
          type: string
          const: failed
          title: Status
          description: Automation processing ended unsuccessfully. The error code
            describes the purchase outcome and next steps.
        dry_run:
          type: boolean
          title: Dry Run
          description: Whether this request evaluates selection without purchasing
            a label.
        shipment_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Shipment Id
        decision_log_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Decision Log Id
        selected_rate:
          anyOf:
          - $ref: '#/components/schemas/SelectedRate'
          - type: 'null'
        transaction_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Transaction Id
        error:
          $ref: '#/components/schemas/ErrorBody'
        evaluated_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Evaluated At
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - request_id
      - test
      - status
      - dry_run
      - error
      - created_at
      title: FailedStatus
      examples:
      - request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        test: false
        status: failed
        dry_run: false
        error:
          code: address_validation_failed
          message: An address could not be validated. Check the address details.
        created_at: '2026-09-03T18:04:10Z'
      - request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        test: false
        status: failed
        dry_run: false
        shipment_id: 5e40ead7cffe4cc1ad45108696162e42
        transaction_id: 9b2d4f6a8c0e4a1b3d5f7a9c1e3b5d7f
        error:
          code: pipeline_dropped_purchase_unresolved
          message: The label purchase was submitted but its outcome could not be confirmed.
            Please check the transaction before retrying to avoid a duplicate label.
        created_at: '2026-09-03T18:04:10Z'
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    NoMatchStatus:
      properties:
        request_id:
          type: string
          format: uuid
          title: Request Id
        test:
          type: boolean
          title: Test
          description: Whether this request was created in test mode.
        status:
          type: string
          const: no_match
          title: Status
          description: No eligible rate was selected; no purchase was attempted. See
            reason for the explanation.
        reason:
          $ref: '#/components/schemas/ReasonBody'
          description: Why no rate was selected. This is a non-error outcome; branch
            on code, not message.
        dry_run:
          type: boolean
          title: Dry Run
          description: Whether this request evaluates selection without purchasing
            a label.
        shipment_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Shipment Id
        decision_log_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Decision Log Id
        evaluated_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Evaluated At
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - request_id
      - test
      - status
      - reason
      - dry_run
      - created_at
      title: NoMatchStatus
      examples:
      - request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        test: false
        status: no_match
        dry_run: false
        reason:
          code: no_match
          message: No rate was selected by your rules or fallback.
        created_at: '2026-09-03T18:04:10Z'
      - request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        test: false
        status: no_match
        dry_run: true
        reason:
          code: all_rates_excluded
          message: No returned rates were eligible for automatic selection.
        created_at: '2026-09-03T18:04:10Z'
      - request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        test: false
        status: no_match
        dry_run: false
        reason:
          code: no_rates_returned
          message: We couldn't find rates for this shipment. Review your details and
            try again.
        created_at: '2026-09-03T18:04:10Z'
    ParcelCreate:
      properties:
        template:
          anyOf:
          - type: string
            minLength: 1
          - type: 'null'
          title: Template
          description: Carrier package template token (e.g. "USPS_FlatRateEnvelope").
            When set, the template supplies the dimensions and length/width/height/distance_unit
            may be omitted.
        length:
          anyOf:
          - type: string
            minLength: 1
          - type: 'null'
          title: Length
          description: Length (unit set by distance_unit). Required unless `template`
            is set.
        width:
          anyOf:
          - type: string
            minLength: 1
          - type: 'null'
          title: Width
          description: Width (unit set by distance_unit). Required unless `template`
            is set.
        height:
          anyOf:
          - type: string
            minLength: 1
          - type: 'null'
          title: Height
          description: Height (unit set by distance_unit). Required unless `template`
            is set.
        distance_unit:
          anyOf:
          - type: string
            minLength: 1
          - type: 'null'
          title: Distance Unit
          description: Unit for length/width/height (e.g. "in", "cm"). Required unless
            `template` is set.
        weight:
          type: string
          minLength: 1
          title: Weight
          description: Weight (unit set by mass_unit).
        mass_unit:
          type: string
          minLength: 1
          title: Mass Unit
          description: Unit for weight (e.g. "lb", "kg").
      additionalProperties: true
      type: object
      required:
      - weight
      - mass_unit
      title: ParcelCreate
      description: 'An inline Shippo parcel. Give its dimensions one of two ways:
        `length`, `width`, `height`, and `distance_unit`, or a carrier package `template`
        that supplies them. `weight` and `mass_unit` are always required, because
        a template sets the box size but not the weight of its contents. To reuse
        a parcel you already created, pass its `object_id` string instead. Any other
        valid Shippo parcel field (for example `metadata`, `extra`) is accepted and
        passed through unchanged.'
    ProcessingStatus:
      properties:
        request_id:
          type: string
          format: uuid
          title: Request Id
        test:
          type: boolean
          title: Test
          description: Whether this request was created in test mode.
        status:
          type: string
          const: processing
          title: Status
          description: Automation processing is still in progress.
        dry_run:
          type: boolean
          title: Dry Run
          description: Whether this request evaluates selection without purchasing
            a label.
        created_at:
          type: string
          format: date-time
          title: Created At
        message:
          type: string
          title: Message
      type: object
      required:
      - request_id
      - test
      - status
      - dry_run
      - created_at
      - message
      title: ProcessingStatus
      examples:
      - request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        test: false
        status: processing
        dry_run: false
        created_at: '2026-09-03T18:04:10Z'
        message: Fetching rates.
    PurchasedStatus:
      properties:
        request_id:
          type: string
          format: uuid
          title: Request Id
        test:
          type: boolean
          title: Test
          description: Whether this request was created in test mode.
        status:
          type: string
          const: purchased
          title: Status
          description: The label was purchased.
        dry_run:
          type: boolean
          title: Dry Run
          description: Whether the request was submitted as a dry run. Normally false
            for purchased requests; use status to determine the purchase outcome.
        shipment_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Shipment Id
        transaction_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Transaction Id
        tracking_number:
          anyOf:
          - type: string
          - type: 'null'
          title: Tracking Number
        label_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Label Url
        selected_rate:
          anyOf:
          - $ref: '#/components/schemas/SelectedRate'
          - type: 'null'
        matched_rule_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Matched Rule Name
        matched_priority:
          anyOf:
          - type: integer
          - type: 'null'
          title: Matched Priority
        fallback_triggered:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Fallback Triggered
        decision_log_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Decision Log Id
        evaluated_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Evaluated At
        label_processed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Label Processed At
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - request_id
      - test
      - status
      - dry_run
      - created_at
      title: PurchasedStatus
      examples:
      - request_id: b3b8f6b0-1a2b-4c3d-9e4f-5a6b7c8d9e0f
        test: false
        status: purchased
        dry_run: false
        shipment_id: 5e40ead7cffe4cc1ad45108696162e42
        transaction_id: 9b2d4f6a8c0e4a1b3d5f7a9c1e3b5d7f
        tracking_number: '9400111899223197428490'
        label_url: https://shippo-delivery.s3.amazonaws.com/2f8b6d1e4a9c4f3b8e7d5a1c6b9e0f24.pdf
        selected_rate:
          rate_id: c4e8a2f6d0b94c17a3e5f7b9d1c3e5a7
          carrier: USPS
          service_level: usps_priority
          amount: '7.35'
        matched_rule_name: default
        matched_priority: 1
        fallback_triggered: false
        decision_log_id: c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f
        evaluated_at: '2026-09-03T18:04:12Z'
        label_processed_at: '2026-09-03T18:04:20Z'
        created_at: '2026-09-03T18:04:10Z'
    ReasonBody:
      properties:
        code:
          type: string
          title: Code
          description: Stable non-error reason code. Integrations must tolerate additional
            codes.
        message:
          type: string
          minLength: 1
          title: Message
          description: Customer-safe explanation. Wording may change.
      type: object
      required:
      - code
      - message
      title: ReasonBody
    SelectedRate:
      properties:
        rate_id:
          type: string
          title: Rate Id
          description: Shippo rate object id that was selected.
        carrier:
          type: string
          title: Carrier
          description: Carrier of the selected rate (e.g. "USPS").
        service_level:
          type: string
          title: Service Level
          description: Service-level token of the selected rate (e.g. "usps_priority").
        amount:
          type: string
          title: Amount
          description: Rate amount as a decimal string, matching the Shippo rate contract
            (e.g. "7.50").
      type: object
      required:
      - rate_id
      - carrier
      - service_level
      - amount
      title: SelectedRate
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
  securitySchemes:
    ShippoToken:
      type: apiKey
      in: header
      name: Authorization
      x-token-prefix: ShippoToken
      x-token-format: ShippoToken {token}
      x-default: 'ShippoToken '
      description: 'Shippo API token, sent as `Authorization: ShippoToken <API_TOKEN>`.'
tags:
- name: Automations
  description: Rules-based, single-call label purchase. Create a request, list requests,
    poll a request's status, and read the decision behind a selected rate.
externalDocs:
  description: Shippo API reference, including the full shipment field list
  url: https://docs.goshippo.com/api-reference/shipments/create-a-new-shipment
security:
- ShippoToken: []
