openapi: 3.1.0
info:
  title: Labels API
  description: API for managing label requests
  version: "v1"
servers:
  - url: https://api.loopreturns.com/api/2026-10
    description: 2026-10 (Stable)
  - url: https://api.loopreturns.com/api/2026-07
    description: 2026-07
  - url: https://api.loopreturns.com/api/unstable
    description: Unstable (Preview)
tags:
  - name: Label Requests
paths:
  /label-requests:
    get:
      summary: List Label Requests
      description: |
        Retrieve a list of label requests.

        The `status` query parameter accepts exactly three values — `issued`, `cancelled`, or
        `fulfilled`. There is no separate status for a request that has reported an error: a
        label request with one or more entries in its `errors` array remains `issued` and will
        keep appearing in `status=issued` results until it is fulfilled or cancelled. An
        integration that polls this endpoint should track which ids it has already reported
        errors for, since the status alone will not reveal that — though each returned
        `LabelRequestResponse` does carry that `errors` array, so a poller can also detect an
        already-errored request directly from the payload.

        #### Required API key scope
        - Label Requests (Read)
      operationId: list-label-requests
      tags:
        - Label Requests
      security:
        - oauth2: ["label_requests:read"]
        - label-requests-read: []
      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/LabelRequestResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
      parameters:
        - in: query
          name: from
          description: Returns label requests after or equal to a minimum date.
          schema:
            $ref: "#/components/schemas/Date"
        - in: query
          name: to
          description: Returns label requests before a maximum date.
          schema:
            $ref: "#/components/schemas/Date"
        - in: query
          name: return_id
          description: Return label requests associated with a specific return_id.
          schema:
            type: integer
            example: 67329889100573
        - in: query
          name: status
          schema:
            $ref: "#/components/schemas/LabelRequestStatusEnum"
        - in: query
          name: limit
          description: The per page limit of label requests to return
          schema:
            type: integer
            default: 50
            minimum: 0
            maximum: 250
        - in: query
          name: offset
          description: The number of label requests to offset.
          schema:
            type: integer
            minimum: 0
  /label-requests/{id}:
    get:
      summary: Get Label Request
      description: |
        Get details about a single label request.

        #### Required API key scope
        - Label Requests (Read)
      operationId: get-label-request
      tags:
        - Label Requests
      security:
        - oauth2: ["label_requests:read"]
        - label-requests-read: []
      parameters:
        - in: path
          name: id
          schema:
            type: integer
            example: 67329889100573
          required: true
          description: The unique identifier for the label request, created by Loop.
      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelRequestResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /label-requests/{id}/errors:
    post:
      summary: Create Label Request Error
      description: |
        Report a label generation failure against a label request.

        The error is recorded against the label request and surfaced to the merchant on the
        return's timeline in Loop admin. Reporting an error does **not** change the label
        request's `status`, trigger a retry, issue a new label request, send a webhook, or
        notify the shopper — the request remains `issued`.

        A label request that has reported one or more errors can still be fulfilled
        afterwards by calling `POST /labels` with the same `id`. This is the recommended way
        to recover from a transient failure.

        Reporting an error against a label request that is already `fulfilled` or `cancelled`
        returns `404 Label request not found.` That response does not necessarily mean the
        `id` is unknown — it can also mean the request is no longer open.

        #### Required API key scope
        - Label Requests (Write)
      operationId: create-label-request-error
      tags:
        - Label Requests
      security:
        - oauth2: ["label_requests:write"]
        - label-requests-write: []
      parameters:
        - in: path
          name: id
          schema:
            type: integer
            example: 67329889100573
          required: true
          description: The unique identifier for the label request, created by Loop.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateLabelRequestErrorRequest"
      responses:
        "202":
          description: Accepted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelRequestErrorResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: |
            The label request could not be found, or is no longer open — this response is
            also returned when the label request is already `fulfilled` or `cancelled`, so
            receiving it does not prove the `id` itself is unknown.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelOperationError"
              example:
                errors: "Label request not found."
        "422":
          $ref: "#/components/responses/Unprocessable"
        "500":
          description: An unexpected error occurred while recording the label request error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelOperationError"
              example:
                errors: "Error recording label request error."
  /labels:
    post:
      summary: Create Label
      description: |
        Create a label for a label request.

        This endpoint may legitimately be called for a label request that previously
        reported one or more errors via `POST /label-requests/{id}/errors` — that is how a
        transient failure is recovered. On success it moves the label request's `status` to
        `fulfilled`. The `id` returned in this endpoint's response identifies the created
        label, not the label request — it is that label `id`, not the label request id, that
        `PUT /labels/{id}` takes.

        #### Required API key scopes
        - Labels (Write)

      operationId: create-label-request-label
      tags:
        - Label Requests
      security:
        - oauth2: ["labels:write"]
        - labels-write: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateLabelRequest"
      responses:
        "201":
          description: Created
          headers:
            Location:
              description: |
                URL of the created label's status-update endpoint (`PUT /labels/{id}`).
              schema:
                type: string
              example: "https://api.loopreturns.com/api/v1/labels/67329889100573"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: The associated label request could not be found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelOperationError"
              example:
                errors: "Label request not found."
        "422":
          $ref: "#/components/responses/Unprocessable"
        "500":
          description: An unexpected error occurred while creating the label.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelOperationError"
              example:
                errors: "Error posting label create request."
  /labels/{id}:
    put:
      summary: Update Label Status
      description: |
        Push a status update for a label. Required for carriers Loop doesn't track
        automatically. For supported carriers, Loop already tracks third-party labels and
        updates their status, so this call isn't needed. See the [Third Party Labels
        integration guide](/integration-guides/labels-integration) for details.

        Calling this endpoint doesn't turn off automatic tracking. For a supported carrier,
        both update the same label status, and the most recent update wins.

        #### Required API key scope
        - Labels (Write)
      operationId: update-label-status
      tags:
        - Label Requests
      security:
        - oauth2: ["labels:write"]
        - labels-write: []
      parameters:
        - in: path
          name: id
          schema:
            type: integer
            example: 67329889100573
          required: true
          description: |
            The unique identifier for the label, created by Loop. This is the identifier that is
            returned from the Create Label request.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateLabelStatusRequest"
      responses:
        "204":
          description: No Content
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          description: The label could not be found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelOperationError"
              example:
                errors: "Label not found."
        "422":
          $ref: "#/components/responses/Unprocessable"
        "500":
          description: An unexpected error occurred while updating the label.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelOperationError"
              example:
                errors: "Error updating label."
  /returns/{returnId}/labels:
    post:
      summary: Generate Label
      description: |
        Queue label generation for a return. This endpoint triggers an asynchronous label generation
        process for the specified return.

        #### Required API key scope
        - Returns

        #### Retrieving the Generated Label

        After the label generation is queued (202 response), the label will be processed asynchronously.
        Once generation is complete, you can retrieve the label data by calling the
        [Get Return Details](/api-reference/latest/return-data/get-return-details) endpoint:

        ```
        GET /warehouse/return/details?return_id={returnId}
        ```

        The response will include a `labels` array containing the generated label with:
        - `url`: The link to the shipping label PDF
        - `tracking_number`: The tracking number for the shipment
        - `carrier`: The shipping carrier (e.g., USPS, UPS)
        - `status`: The current status of the label
        - `rate`: The shipping cost

        #### Successful Response
        Returns HTTP 202 (Accepted) when the label generation has been successfully queued.

        #### Error Responses
        - **404 Not Found** (`return_not_found`): The specified return does not exist
        - **409 Conflict** (`label_already_exists`): A label has already been generated for this return
        - **422 Unprocessable Entity** (`return_cannot_receive_label`): The return is not in a valid state to
          receive a label
        - **422 Unprocessable Entity** (`label_generation_failed`): A previous label generation attempt failed
        - **500 Internal Server Error** (`internal_error`): An unexpected error occurred
      operationId: generate-label
      tags:
        - Label Requests
      security:
        - oauth2: ["returns"]
        - returns: []
      parameters:
        - in: path
          name: returnId
          schema:
            type: integer
            example: 12345
          required: true
          description: The unique identifier for the return, created by Loop.
      responses:
        "202":
          description: Label generation queued successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GenerateLabelResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/GenerateLabelNotFound"
        "409":
          $ref: "#/components/responses/GenerateLabelConflict"
        "422":
          $ref: "#/components/responses/GenerateLabelUnprocessableEntity"
        "500":
          $ref: "#/components/responses/GenerateLabelInternalError"
  /returns/{returnId}/labels/regenerate:
    post:
      summary: Regenerate Label
      description: |
        Queue a new Loop label for a return that already has one, for example when the original
        label expired before the shopper dropped off the package. This does the same thing as a
        merchant clicking Regenerate label on the return in Loop admin.

        The request only checks that the return can be regenerated and then queues the work. The
        regeneration runs asynchronously in the background, and the response returns before the new
        label is bought.

        #### Required API key scope
        - Returns

        A key without the Returns scope gets a `403`, even if it has Labels write.

        #### Which returns can be regenerated
        - The return must be open.
        - The return must not use third party labels. Third party label returns are not supported
          by this endpoint.
        - The return must not have multiple labels enabled.
        - The return must have exactly one label bought through Loop.
        - That label must still be `new` or `pre_transit`. A label that has been scanned or is
          already in the carrier network (for example `in_transit`, `out_for_delivery`, or
          `delivered`) is left in place and cannot be regenerated.

        #### Retrieving the New Label
        After the request is queued (202 response), call
        [Get Return Details](/api-reference/latest/return-data/get-return-details) to read the new
        label from the `labels` array once it is ready.

        If the background regeneration fails, the failure is stored the same way as for
        [Generate Label](/api-reference/latest/label-requests/generate-label). The old label has
        already been removed at that point, so a retry of this endpoint returns
        `unexpected_label_count`, and a Generate Label call can return `label_generation_failed`.

        #### Successful Response
        Returns HTTP 202 (Accepted) when the label regeneration has been successfully queued.
        A repeat call while a regeneration for the same return is still pending is also accepted
        with 202, and the regeneration is not queued again.

        #### Error Responses
        - **401 Unauthorized**: The request could not be authorized
        - **403 Forbidden**: The API key does not have the Returns scope
        - **404 Not Found** (`return_not_found`): The specified return does not exist
        - **409 Conflict** (`label_in_use`): The label has already been scanned or is in the carrier
          network, so it is not `new` or `pre_transit`. The existing label is left in place
        - **422 Unprocessable Entity** (`return_not_open`): The return is not open
        - **422 Unprocessable Entity** (`third_party_labels_not_supported`): The return uses third party
          labels
        - **422 Unprocessable Entity** (`unexpected_label_count`): The return does not have exactly one
          label bought through Loop, or the return has multiple labels enabled. This is also returned
          when no label is left after a failed regeneration
        - **422 Unprocessable Entity** (`label_generation_failed`): A previous label generation or
          regeneration job for this return failed
      operationId: regenerate-label
      tags:
        - Label Requests
      security:
        - oauth2: ["returns"]
        - returns: []
      parameters:
        - in: path
          name: returnId
          schema:
            type: integer
            example: 12345
          required: true
          description: The unique identifier for the return, created by Loop.
      responses:
        "202":
          description: Label regeneration queued successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GenerateLabelResponse"
              example:
                message: "Label regeneration queued"
                returnId: 12345
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: The API key does not have the Returns scope.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LabelOperationError"
              example:
                errors: "Unauthorized."
        "404":
          $ref: "#/components/responses/GenerateLabelNotFound"
        "409":
          $ref: "#/components/responses/RegenerateLabelConflict"
        "422":
          $ref: "#/components/responses/RegenerateLabelUnprocessableEntity"
components:
  schemas:
    LabelStatusEnum:
      type: string
      description: The label status values accepted when updating a label.
      enum:
        - "new"
        - "pre_transit"
        - "in_transit"
        - "out_for_delivery"
        - "delivered"
      example: "new"
    LabelFullStatusEnum:
      type: string
      description: The current status of the label.
      enum:
        - "queueable"
        - "queued"
        - "queued_for_purchase"
        - "purchase_failed"
        - "new"
        - "pre_transit"
        - "in_transit"
        - "out_for_delivery"
        - "delivered"
        - "available_for_pickup"
        - "cancelled"
        - "unknown"
        - "return_to_sender"
        - "failure"
        - "error"
        - "refund_requested"
      example: "new"
    LabelRequestStatusEnum:
      type: string
      description: The status of the label request.
      enum:
        - "issued"
        - "cancelled"
        - "fulfilled"
      example: "issued"
    ErrorReasonEnum:
      type: string
      description: The error reason.
      enum:
        - "INSUFFICIENT_FUNDS"
        - "INVALID_ADDRESS"
        - "Other"
      example: "INVALID_ADDRESS"
    Address:
      type: object
      properties:
        name:
          type:
            - string
            - "null"
          maxLength: 100
          description: The recipient's name.
        company:
          type:
            - string
            - "null"
          maxLength: 100
          description: The recipient's company.
        address1:
          type: string
          maxLength: 125
          description: The recipient's street address.
        address2:
          type:
            - string
            - "null"
          maxLength: 125
          description: The recipient's secondary address details (such as unit number or PO box information).
        city:
          type: string
          maxLength: 100
          description: The city in which the address is located.
        state:
          type:
            - string
            - "null"
          maxLength: 100
          description: The state or region in which the address is located.
        zip:
          type: string
          maxLength: 16
          description: The postal code associated with the address.
        country:
          type: string
          maxLength: 100
          description: The country in which the address is located.
        country_code:
          type: string
          maxLength: 2
          description: The two-letter country code associated with the address.
        phone:
          type:
            - string
            - "null"
          description: The phone number associated with the address.
      required:
        - address1
        - city
        - zip
        - country
        - country_code
      example:
        name: "John Smith"
        company: "Acme, Co"
        address1: "123 Example St"
        address2: "Box 123"
        city: "Columbus"
        state: "OH"
        zip: "12345"
        country: "United States of America"
        country_code: "US"
        phone: "+1 555-555-5555"
    Product:
      type: object
      required:
        - name
        - sku
        - price
      properties:
        name:
          type: string
          description: The name of the product.
          example: "Product Name"
        price:
          $ref: "#/components/schemas/MoneySet"
        country_of_origin:
          type:
            - string
            - "null"
          description: The country of origin of the product.
          example: "USA"
        hs_code:
          type:
            - string
            - "null"
          description: The HS (Harmonized System) code of the product.
          example: "61051000"
        sku:
          type: string
          description: The SKU of the product.
          example: "99999999"
    MoneySet:
      type: object
      example:
        - amount: 50000
          currency: "USD"
        - amount: 25000
          currency: "CAD"
        - amount: 1500
          currency: "EUR"
      properties:
        amount:
          type: integer
          format: int32
          description: The amount represented in cents.
          example: 25000
        currency:
          type:
            - string
          default: "USD"
          example: "EUR"
          description: The 3 character (ISO 4217) currency code.
      required:
        - amount
        - currency
    MoneySetData:
      type: object
      example:
        - amount: 50000
          currency_code: "USD"
        - amount: 25000
          currency_code: "CAD"
        - amount: 1500
          currency_code: "EUR"
      properties:
        amount:
          type: integer
          format: int32
          description: The amount represented in cents.
          example: 25000
        currency_code:
          type: string
          example: "EUR"
          description: The 3 character (ISO 4217) currency code.
      required:
        - amount
        - currency_code
    Date:
      type: string
      description: |
        A date-time value in ISO 8601 format. What it represents (for example, when a label,
        label request, or reported error was created, or a date-range filter bound) depends on
        the field or parameter referencing this schema.
      format: date-time
      example: "2023-04-25T13:25:00-05:00"
    CreateLabelRequestErrorRequest:
      type: object
      properties:
        reason:
          description: The reason code associated with the label request error.
          $ref: "#/components/schemas/ErrorReasonEnum"
        message:
          type:
            - string
            - "null"
          maxLength: 500
          description: The message associated with the label request error.
          example: "Failed to generate a label, the origin address is invalid"
      required:
        - reason
    UpdateLabelStatusRequest:
      type: object
      properties:
        status:
          $ref: "#/components/schemas/LabelStatusEnum"
      required:
        - status
    LabelRequestErrorResponse:
      type: object
      required:
        - reason
      properties:
        reason:
          description: The reason code associated with the label request error.
          $ref: "#/components/schemas/ErrorReasonEnum"
        message:
          type:
            - string
            - "null"
          description: The message associated with the label request error.
          example: "Failed to generate a label, the origin address is invalid"
        created_at:
          $ref: "#/components/schemas/Date"
    CreateLabelRequest:
      type: object
      properties:
        label_request_id:
          type: integer
          description: The label request id this label applies to.
          example: 67329889100573
        tracking_number:
          type: string
          maxLength: 256
          description: The tracking number associated with the label.
          example: "9400136105440512280610"
        tracking_url:
          type:
            - string
            - "null"
          maxLength: 2048
          description: |
            The tracking URL associated with the label. Strongly recommended — it gives the
            shopper a working tracking link right away, even before Loop's automatic status
            tracking (see `carrier`) produces an update.
          example: "https://tools.usps.com/go/TrackConfirmAction_input?strOrigTrackNum=9400136105440512280610"
        carrier:
          type: string
          maxLength: 32
          description: |
            The carrier's standard name in lowercase (for example `usps`, `fedex`, `ups`) — never
            the tracking number or an internal reference. Loop uses this together with
            `tracking_number` to track the shipment automatically, for supported carriers; an
            incorrect value means automatic tracking never starts.
          example: "usps"
        label_url:
          type:
            - string
            - "null"
          maxLength: 2048
          description: |
            The URL containing the printable PDF of the labels.
            Required unless `qrcode_url` is provided.
          example: "https://s3.amazonaws.com/example-bucket/label.pdf"
        qrcode_url:
          type:
            - string
            - "null"
          maxLength: 512
          description: The QR Code URL containing the printable PDF of the labels.
          example: "https://s3.amazonaws.com/example-bucket/qrcode.pdf"
        rate:
          $ref: "#/components/schemas/MoneySetData"
      required:
        - label_request_id
        - tracking_number
        - carrier
        - rate
      anyOf:
        - required:
            - label_url
        - required:
            - qrcode_url
    LabelResponse:
      type: object
      required:
        - id
        - tracking_number
        - carrier
        - rate
        - status
        - created_at
      properties:
        id:
          type: integer
          format: int64
          description: The id of the label you created.
          example: 67329889100573
        tracking_number:
          type: string
          description: The tracking number associated with the label.
          example: "9400136105440512280610"
        tracking_url:
          type:
            - string
            - "null"
          description: The tracking URL associated with the label.
          example: "https://tools.usps.com/go/TrackConfirmAction_input?strOrigTrackNum=9400136105440512280610"
        carrier:
          type: string
          description: The carrier associated with the label.
          example: "usps"
        label_url:
          type:
            - string
            - "null"
          description: The URL containing the printable PDF of the labels.
          example: "https://s3.amazonaws.com/example-bucket/label.pdf"
        qrcode_url:
          type:
            - string
            - "null"
          description: The QR Code URL containing the printable PDF of the labels.
          example: "https://s3.amazonaws.com/example-bucket/qrcode.pdf"
        rate:
          $ref: "#/components/schemas/MoneySetData"
        status:
          $ref: "#/components/schemas/LabelFullStatusEnum"
        created_at:
          $ref: "#/components/schemas/Date"
    LabelRequestResponse:
      type: object
      required:
        - id
        - addresses
        - parcel
        - products
        - errors
        - return_id
        - shop_id
        - status
        - created_at
      properties:
        id:
          type: string
          description: |
            The unique identifier for the label request, created by Loop. Note that this
            field is serialized as a string here, while the `id` path parameter (for example
            on `GET /label-requests/{id}`) and `CreateLabelRequest.label_request_id` are
            integers — callers should not assume a single JSON type for this identifier
            across calls.
          example: "67329889100573"
        addresses:
          type: object
          required:
            - origin
            - destination
          properties:
            origin:
              $ref: "#/components/schemas/Address"
            destination:
              $ref: "#/components/schemas/Address"
        parcel:
          type: object
          required:
            - height
            - length
            - width
            - weight
          properties:
            height:
              type: number
              format: double
              description: The height of the parcel in inches.
              example: 5.0
            length:
              type: number
              format: double
              description: The length of the parcel in inches.
              example: 20.2
            width:
              type: number
              format: double
              description: The width of the parcel in inches.
              example: 10.9
            weight:
              type: number
              format: double
              description: The weight of the parcel in grams.
              example: 65.9
        products:
          type: array
          items:
            $ref: "#/components/schemas/Product"
        errors:
          type: array
          description: |
            An append-only history of errors reported for this label request via
            `POST /label-requests/{id}/errors`. Its presence does not close or cancel the
            request.
          items:
            $ref: "#/components/schemas/LabelRequestErrorResponse"
        return_id:
          type: integer
          format: int64
          description: The return id of the return.
          example: 1001
        shop_id:
          type: integer
          format: int64
          description: The id of the shop belonging to the merchant.
          example: 50
        status:
          $ref: "#/components/schemas/LabelRequestStatusEnum"
        created_at:
          $ref: "#/components/schemas/Date"
    GenerateLabelResponse:
      type: object
      properties:
        message:
          type: string
          description: Confirmation message that label generation has been queued.
          example: "Label generation queued"
        returnId:
          type: integer
          format: int64
          description: The return ID for which label generation was queued.
          example: 12345
      required:
        - message
        - returnId
    LabelOperationError:
      type: object
      description: |
        Error envelope for a label or label-request failure response. Unlike the generic
        error responses, `errors` is a single message string rather than an object or array.
      required:
        - errors
      properties:
        errors:
          type: string
          example: "Label not found."
  responses:
    NotFound:
      description: The requested entity could not be found.
      content:
        application/json:
          schema:
            type: object
            required:
              - message
            properties:
              message:
                type: string
                example: "Resource not found."
    Unauthorized:
      description: The request could not be authorized.
      content:
        application/json:
          schema:
            type: object
            required:
              - errors
            properties:
              errors:
                type: string
                example: "Unauthorized."
    Forbidden:
      description: |
        The authenticated shop is not authorized to act on this resource (for example, the label's
        return belongs to a different shop).
      content:
        application/json:
          schema:
            type: object
            properties:
              message:
                type: string
                example: "This action is unauthorized."
    Unprocessable:
      description: |
        Validation failed. Returned when the request body does not satisfy the endpoint's
        validation rules.
      content:
        application/json:
          schema:
            type: object
            properties:
              message:
                type: string
                example: "The status field is required."
              errors:
                type: object
                additionalProperties:
                  type: array
                  items:
                    type: string
                example:
                  status:
                    - "The status field is required."
    GenerateLabelNotFound:
      description: The specified return could not be found.
      content:
        application/json:
          schema:
            type: object
            properties:
              code:
                type: string
                example: "return_not_found"
              errors:
                type: array
                items:
                  type: string
                example: ["Return not found."]
    GenerateLabelConflict:
      description: A label already exists for this return.
      content:
        application/json:
          schema:
            type: object
            properties:
              code:
                type: string
                example: "label_already_exists"
              errors:
                type: array
                items:
                  type: string
                example: ["Label already exists for return [12345]."]
    GenerateLabelUnprocessableEntity:
      description: The return cannot receive a label or label generation has failed.
      content:
        application/json:
          schema:
            type: object
            properties:
              code:
                type: string
                enum:
                  - "return_cannot_receive_label"
                  - "label_generation_failed"
                example: "return_cannot_receive_label"
              errors:
                type: array
                items:
                  type: string
                example:
                  ["The return is not in a valid state to receive a label."]
    RegenerateLabelConflict:
      description: |
        The return's label has already been scanned or is in the carrier network, so it cannot be
        regenerated. The existing label is left in place.
      content:
        application/json:
          schema:
            type: object
            properties:
              code:
                type: string
                enum:
                  - "label_in_use"
                example: "label_in_use"
              errors:
                type: array
                items:
                  type: string
                example: ["Return [12345] has a label that is already in use."]
    RegenerateLabelUnprocessableEntity:
      description: |
        The return is not eligible for label regeneration, or a previous label generation job for
        this return failed.
      content:
        application/json:
          schema:
            type: object
            properties:
              code:
                type: string
                enum:
                  - "return_not_open"
                  - "third_party_labels_not_supported"
                  - "unexpected_label_count"
                  - "label_generation_failed"
                example: "return_not_open"
              errors:
                type: array
                items:
                  type: string
                example: ["Return [12345] is not open."]
    GenerateLabelInternalError:
      description: An internal server error occurred.
      content:
        application/json:
          schema:
            type: object
            properties:
              code:
                type: string
                example: "internal_error"
              errors:
                type: array
                items:
                  type: string
                example: ["Error processing label request."]
  securitySchemes:
    oauth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://oauth.loopreturns.com/authorize
          tokenUrl: https://oauth.loopreturns.com/oauth/token
          scopes:
            "labels:read": Read access to labels
            "labels:write": Create and modify labels
            "label_requests:read": Read access to label requests
            "label_requests:write": Create and modify label requests
            "returns": Access to returns operations
    developer-tools:
      type: apiKey
      in: header
      name: X-Authorization
      description: 'API Scope: "Developer Tools"'
      x-scope: Developer Tools
    labels-read:
      type: apiKey
      in: header
      name: X-Authorization
      description: 'API Scope: "Labels (read)"'
      x-scope: Labels (Read)
    label-requests-read:
      type: apiKey
      in: header
      name: X-Authorization
      description: 'API Scope: "Label Requests (read)"'
      x-scope: Label Requests (Read)
    labels-write:
      name: X-Authorization
      type: apiKey
      in: header
      description: 'API Scope: "Labels (write)"'
      x-scope: Labels (Write)
    label-requests-write:
      name: X-Authorization
      type: apiKey
      in: header
      description: 'API Scope: "Label Requests (write)"'
      x-scope: Label Requests (Write)
    returns:
      name: X-Authorization
      type: apiKey
      in: header
      description: 'API Scope: "Returns"'
      x-scope: Returns
