> ## Documentation Index
> Fetch the complete documentation index at: https://docs.loopreturns.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Draft Return Totals

> Returns the computed monetary totals for the draft return. Money values are objects with
an integer `amount` in minor units and a `currencyCode`.




## OpenAPI

````yaml draft-returns-hal-forms get /draft-returns/{draft_return_id}/totals
openapi: 3.1.0
info:
  title: Draft Returns API
  version: v1
  description: >
    # Overview


    The Draft Returns API lets you build a complete return-creation flow by
    managing draft

    returns through a state machine. Endpoints allow you to initialize a draft,
    add or remove

    items, set customer and address details, finalize selections, and submit the
    completed return.


    This document describes the API as of version `2026-10`. Use

    `/api/2026-10/draft-returns/...` for production or
    `/api/unstable/draft-returns/...` to test upcoming changes.


    ## Response architecture


    Successful responses include `draft_return`, `context`, `errors`, plus
    hypermedia controls.


    ### `_links`


    An object keyed by relation name. Each value includes `href` and optional
    metadata:


    ```json

    {
      "_links": {
        "self": {
          "href": "https://api.loopreturns.com/api/2026-10/draft-returns/123"
        },
        "add-returning-item": {
          "href": "https://api.loopreturns.com/api/2026-10/draft-returns/123/returning-items"
        },
        "finalize-items": {
          "href": "https://api.loopreturns.com/api/2026-10/draft-returns/123/finalize-items"
        }
      }
    }

    ```


    ### `_templates`


    Each available action is described by a template in the `_templates` object:


    ```json

    {
      "_templates": {
        "add-returning-item": {
          "method": "POST",
          "title": "Add a line item to the return",
          "contentType": "application/json",
          "properties": [
            {
              "name": "order_line_item_id",
              "type": "number",
              "required": true,
              "prompt": "ID of the line item to return"
            }
          ]
        },
        "finalize-items": {
          "method": "POST",
          "title": "Lock in item selections and proceed",
          "contentType": "application/json",
          "properties": []
        }
      }
    }

    ```


    Each template may include:

    - `method`: The HTTP method (`POST`, `DELETE`, etc.)

    - `title`: Human-readable description of the action

    - `contentType`: The request content type (typically `application/json`)

    - `properties`: Array of field descriptors with `name`, `type`, `required`,
      `prompt`, and optionally `options` (for enum-like fields)
    - `required`: `true` when the action must be completed before the draft
    return can
      progress, for example while a label format still has to be picked. This flag belongs
      to the template. It is separate from `required` on each entry in `properties`, which
      only says whether that field must be sent in the request body
    - `systemMessage`: Only on a yes/no `add-returning-item-user-input`
    template, when the
      merchant turned on a "Response if yes" message. See User input below

    Whether an action's template is present, and its `required` flag, describe
    only that one

    action, not the draft return as a whole. The only reliable signal that the
    draft return is

    ready to submit is the presence of the `submit-draft-return` template.


    ### `client_application`


    Responses include a `client_application` object describing how the client
    should

    identify itself on subsequent requests.


    ### Content type


    | Header | Value |

    |---|---|

    | `Accept` (request) | `application/prs.hal-forms+json` |

    | `Content-Type` (response) | `application/prs.hal-forms+json` |

    | `Content-Type` (request body) | `application/json` |


    Requests to version `2026-10` or later always return HAL-Forms format
    regardless of the

    `Accept` header, on every endpoint including `GET /draft-returns` (List). On
    earlier versions

    such as `2026-07`, send `Accept: application/prs.hal-forms+json` to get
    HAL-Forms; without that

    header, those versions respond with `application/json` and send merchant
    questions and messages

    as plain text. On those earlier versions, List is the exception: it requires
    the HAL-FORMS

    `Accept` header and returns `422` `unsupported-feature` when the header is
    missing or is

    `application/json`.


    ### Shopper token


    Shopper-portal draft responses include `shopper_token`.

    Send that value as `X-Loop-Shopper-Token` on later shopper-portal requests
    that include a

    draft return id. Merchant public API responses omit this field and do not
    require the header.

    A missing, empty, or non-matching token on those draft-id requests returns
    `404`.

    Create, initialize, and list do not require the header.


    ## State Machine


    ```

    created → finalize-items → items-finalized → submit → submitted
       ↓                              ↓
       ↓← ← unfinalize-items ← ← ← ← ↓
       ↓                              ↓
       └→ cancel → cancelled     expired
    ```


    ### States


    - **created**: Initial state where items are added and customer information
    is set

    - **items-finalized**: Items are locked in; credit type and return method
    can be selected

    - **submitted**: Terminal state — draft has been converted to an actual
    return

    - **cancelled**: Terminal state — draft was explicitly cancelled

    - **expired**: Terminal state — draft timed out due to inactivity


    ### Available Templates by State


    #### Created State


    `_templates` may include:


    - `add-returning-item`: Add an item from the order to the return

    - `remove-returning-item`: Remove an item from the return

    - `set-returning-item-return-reason`: Set why an item is being returned

    - `set-returning-item-return-type`: Set the return type for an item. Send
    only a value
      from that item's template `options`
    - `add-returning-item-exchange-item`: Add an exchange product for a
    returning item

    - `add-returning-item-user-input`: Provide additional information requested
    by merchant

    - `remove-cart-item`: Remove an exchange or shop-now item

    - `set-customer`: Set customer email and name

    - `set-address`: Set return shipping address

    - `finalize-items`: Lock in item selections and proceed to return method
    selection

    - `cancel-draft-return`: Cancel this draft return


    #### Items-Finalized State


    `_templates` may include:


    - `set-credit-type`: Choose how to receive the refund

    - `set-processing-type`: Choose `regular` or `instant` processing. See
    Processing type below

    - `select-return-method`: Select the shipping method for the return

    - `add-payment-intent`: Attach a payment intent when the draft return
    requires a payment.
      Not offered when the shop has no usable Stripe connection.
    - `submit-draft-return`: Submit the draft and convert it to an actual return

    - `unfinalize-items`: Go back to add/remove items

    - `cancel-draft-return`: Cancel this draft return


    #### Terminal States


    When a draft return reaches a terminal state (`submitted`, `cancelled`,
    `expired`),

    `_templates` and `_links` will be empty objects.


    ## User input


    Each unanswered merchant question on a returning item has its own

    `add-returning-item-user-input` template. Its `title` is the question as
    HTML, because

    merchants can format questions. After the shopper answers, the question is
    in

    `returning_items[].user_inputs[]` with the same HTML in `prompt`. Sanitize
    this HTML before

    you show it.


    A yes/no template can include `systemMessage`, the merchant's "Response if
    yes" message.

    It is only present when the merchant turned that response on. Show it when
    the shopper

    answers `Yes`. If the merchant's rule rejects the item on `Yes`, the item is
    removed from the

    draft return and the next response does not include the message. Keep it
    from the template

    before you submit the answer, show it, then return the shopper to item
    selection.


    ```json

    {
      "_templates": {
        "add-returning-item-user-input:1:10": {
          "method": "POST",
          "title": "<p>Have the seals been broken?</p>",
          "systemMessage": "<p>Used cartridges cannot be returned.</p>"
        }
      }
    }

    ```


    ## Processing type


    `processing_type` is `regular` or `instant`. Every draft return starts as
    `regular`.


    In the `items-finalized` state, `_embedded.processing_type_options` shows
    whether each

    processing type is available, and the amounts for Instant. To change the
    processing type,

    use the `set-processing-type` template and send only a value from its
    `options`.


    When the draft has an exchange item, Instant runs as Instant Exchange. It
    stays available

    even when the credit type is `refund`.


    ### Instant reset


    While the draft is in `items-finalized`, Loop checks again on every request
    (including

    `GET` and submit) whether Instant is still available. If it is not, Loop:


    - sets `processing_type` to `regular`

    - removes the payment intent, so `payment_intent` is `null`


    Before you submit, read `processing_type` and `payment_intent` in the latest
    response. If you

    still want Instant and it is available again, set it again and attach a new
    payment intent.


    `unfinalize-items` also sets `processing_type` back to `regular`.


    ## Payment


    A draft return can require a payment, for example when the shopper owes
    money after

    exchanging into a pricier item, or when `processing_type` is `instant`. Loop
    collects it

    through the shop's Stripe connection:


    - If the shop has a usable Stripe connection, the `add-payment-intent`
    template is offered
      and marked required. Call it before you submit.
    - If the shop has no usable Stripe connection, Loop cannot collect the
    payment. The
      `add-payment-intent` template and link are not offered, and `requires_uncollectible_payment`
      is `true`. The draft return cannot be submitted in this state. To continue, change the
      draft so no payment is needed, for example by changing items or the return method.

    If Instant stops being available, Loop resets `processing_type` to `regular`
    and removes the

    payment intent, so `payment_intent` comes back `null`. Check
    `processing_type` and

    `payment_intent` before you submit. If a payment is still needed,
    `add-payment-intent` is

    offered again.
servers:
  - url: https://api.loopreturns.com/api/2026-10
    description: 2026-10 (Stable)
  - url: https://api.loopreturns.com/api/unstable
    description: Unstable (Preview)
security: []
paths:
  /draft-returns/{draft_return_id}/totals:
    get:
      summary: Get Draft Return Totals
      description: >
        Returns the computed monetary totals for the draft return. Money values
        are objects with

        an integer `amount` in minor units and a `currencyCode`.
      operationId: getDraftReturnTotalsHalForms
      parameters:
        - $ref: '#/components/parameters/DraftReturnId'
        - $ref: '#/components/parameters/ShopId'
        - $ref: '#/components/parameters/AcceptHalForms'
        - $ref: '#/components/parameters/ShopperToken'
      responses:
        '200':
          description: OK
          content:
            application/prs.hal-forms+json:
              schema:
                type: object
                properties:
                  _links:
                    $ref: '#/components/schemas/HalFormsLinks'
                  data:
                    type: object
                    properties:
                      return_total:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      new_item_total:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      total_bonus_offered:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      bonus_used:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      fees:
                        type: object
                        properties:
                          applied:
                            $ref: '#/components/schemas/DraftReturnMoney'
                          refund:
                            $ref: '#/components/schemas/DraftReturnMoney'
                          credit:
                            $ref: '#/components/schemas/DraftReturnMoney'
                          exchange:
                            $ref: '#/components/schemas/DraftReturnMoney'
                      amount_due:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      credit:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      net:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      returning_item_subtotal:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      returning_item_tax:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      purchasing_item_tax:
                        $ref: '#/components/schemas/DraftReturnMoney'
                      settings:
                        type: object
                        properties:
                          stripe_min:
                            type: integer
                      is_difference_covered:
                        type: boolean
                        description: >
                          `true` when the shopper does not pay a price
                          difference that exists, because the

                          merchant covers it. This happens in two cases:


                          - The amount the shopper owes is below
                          `settings.stripe_min`, so it is waived.

                          - Nothing is due, and at least one new item costs more
                          than the item it replaces.


                          A discount carried over from the original order does
                          not count as a difference. An

                          even exchange returns `false`, even when the new
                          item's price includes that discount.
                        example: false
                      qualifies_for_return_coverage:
                        type: boolean
                        description: >
                          `true` when at least one returned item is covered by
                          the order's Returns Coverage, so

                          the handling fee is waived. One covered item covers
                          the whole return. The `fees`

                          amounts still show the configured fee, but
                          `amount_due` and `net` already leave it

                          out. Do not subtract the fee from them again.


                          `false` when the order has no Returns Coverage, or
                          when every returned item is

                          excluded from it by an excluded product tag or
                          discount code.
                        example: false
                      new_item_prices:
                        type: array
                        description: >
                          The price the shopper pays for each new item, with any
                          discount carried over from the

                          original order. Use it to show the shopper what each
                          new item costs them.


                          - There is one entry per new item, so two returned
                          items exchanged for the same variant
                            each have their own entry. Match entries on `order_line_item_id`, not `variant_id`.
                          - When the shopper pays the price difference for an
                          exchange, that item has no entry.
                            The shopper pays the catalog price, so show that.
                          - The list is empty when the draft return has no new
                          items.
                        items:
                          type: object
                          properties:
                            order_line_item_id:
                              type:
                                - integer
                                - 'null'
                              description: >
                                The order line item being returned that this new
                                item replaces. `null` for an

                                item added from the shop rather than exchanged
                                for a returned item.
                              example: 11
                            variant_id:
                              type: string
                              description: >
                                The product variant of the new item. Sent as a
                                string, not a number, so large

                                ids stay exact.
                              example: '1234567890123456789'
                            price:
                              type: integer
                              description: >
                                What the shopper pays for the item, in minor
                                units of the same currency as

                                the other totals in this response.
                              example: 800
                          required:
                            - order_line_item_id
                            - variant_id
                            - price
                        example:
                          - order_line_item_id: 11
                            variant_id: '9999'
                            price: 800
                          - order_line_item_id: null
                            variant_id: '1234567890123456789'
                            price: 900
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/ShopperDraftReturnNotFound'
      security:
        - api_key: []
components:
  parameters:
    DraftReturnId:
      name: draft_return_id
      in: path
      description: The unique identifier of the draft return.
      required: true
      schema:
        type: integer
    ShopId:
      name: X-Shop-Id
      in: header
      description: >
        The unique identifier of the shop associated with the draft return.


        This header is not required, as the merchant's shop is identified by the
        API key present in the request.
      schema:
        type: integer
    AcceptHalForms:
      name: Accept
      in: header
      required: false
      description: >
        Optional. Responses use `Content-Type: application/prs.hal-forms+json`.
        Ignored on `2026-10`

        and later. On earlier versions, send it to receive HAL-Forms, and it is
        required for

        `GET /draft-returns` (List).
      schema:
        type: string
        enum:
          - application/prs.hal-forms+json
    ShopperToken:
      name: X-Loop-Shopper-Token
      in: header
      required: false
      description: >
        Shopper-portal only. The `shopper_token` from a shopper-portal draft
        response.

        Required on shopper-portal requests that include a draft return id.

        A missing, empty, or non-matching value returns `404`.

        Merchant public API requests ignore this header.
      schema:
        type: string
  schemas:
    HalFormsLinks:
      type: object
      description: >
        HAL `_links` object. Always includes `self`. Other keys are relation
        names

        corresponding to available actions for the current draft return state.
      properties:
        self:
          $ref: '#/components/schemas/HalLink'
      additionalProperties:
        $ref: '#/components/schemas/HalLink'
    DraftReturnMoney:
      type: object
      properties:
        amount:
          type: integer
          description: The monetary amount in minor units (e.g. cents).
        currencyCode:
          type: string
          description: The three-character ISO 4217 currency code.
    HalLink:
      type: object
      properties:
        href:
          type: string
          description: The fully-qualified URL for this link relation.
      required:
        - href
  responses:
    UnauthorizedError:
      description: API key is missing or invalid.
      content:
        application/json:
          schema:
            type: object
            properties:
              errors:
                type: array
                items:
                  type: object
                  properties:
                    code:
                      type: string
                      enum:
                        - unauthorized
                    message:
                      type: string
                      example: Unauthorized.
    ShopperDraftReturnNotFound:
      description: |
        Not found. On shopper-portal draft-id requests, also returned when
        `X-Loop-Shopper-Token` is missing, empty, or does not match the draft.
  securitySchemes:
    api_key:
      type: apiKey
      in: header
      name: X-Authorization

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.