> For the complete documentation index, see [llms.txt](https://docs.parcellab.com/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.parcellab.com/docs/developers/returns/connect-order-data/real-time-api-connection-for-returns.md).

# Real-time API Connection for Returns

Use this setup when you want parcelLab to orchestrate returns with live retailer-system integrations instead of relying only on a preloaded order export.

In a typical real-time returns setup, parcelLab:

* gets order data either from an existing push feed or by fetching it on demand
* sends return registration data to the retailer-side warehouse flow as an RMA notification and ASN
* receives the warehouse processing outcome back after the items are inspected
* sends status and close/refund updates back into the retailer-side order flow

{% hint style="info" %}
The same model works whether you use a parcelLab-hosted Returns Portal or embed the Returns Portal on your own site.
{% endhint %}

## Overview

### Retailer-side system split

| System            | Typical responsibility                                                        | Typical interaction with parcelLab                                        |
| ----------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| OMS               | Order master data, customer identity, order state, refund state               | Provides order data to parcelLab and receives order/refund updates back   |
| WMS               | Physical return intake, inspection, acceptance/rejection decisions            | Receives RMA/ASN data from parcelLab and sends the warehouse outcome back |
| parcelLab Returns | Returns Portal, eligibility logic, label orchestration, return communications | Coordinates the flow between shopper, OMS, WMS, and carriers              |

```mermaid
sequenceDiagram
    autonumber
    participant Shopper as Shopper
    participant PL as parcelLab Returns
    participant OMS as Retailer OMS
    participant WMS as Retailer WMS

    Note over OMS,PL: Initial order data can be connected in one of two ways
    OMS->>PL: Push order data via Create Orders/Trackings API
    PL->>OMS: Or fetch order data on demand via GET /orders/{order_reference}
    Shopper->>PL: Register return in the Returns Portal
    PL->>WMS: RMA notification + ASN
    Note over PL,WMS: Later updates can include cancellations or additional labels
    Shopper->>PL: Drop off parcel
    PL->>OMS: Optional return status update to OMS
    WMS->>PL: Received-item outcome and optional refund recommendation
    PL->>OMS: Close return / trigger refund after warehouse decision
```

## Choose How parcelLab Receives Initial Order Data

| Option                          | How it works                                                                                                              | Best when                                                                                         | Main advantage                                               | Main consideration                                                                    |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------- |
| Push via existing outbound feed | Reuse the same retailer feed used for [Create Orders/Trackings](/docs/developers/orders/create-orders-trackings.md)       | You already send order data to parcelLab for Tracking+ or another returns-related flow            | Fast rollout and one shared source for delivery and returns  | parcelLab needs enough order context stored for the relevant return window            |
| Pull via real-time lookup       | Expose a retailer `GET` endpoint that parcelLab calls when the shopper starts a return or eligibility needs to be checked | You want minimal parcelLab-side storage or you support long warranty / long-tail return scenarios | Minimal data storage in parcelLab and always-live order data | The lookup endpoint becomes part of the shopper journey, so latency and uptime matter |

{% hint style="info" %}
If you already have an outbound Tracking+ order feed, push is usually the quickest setup. Pull is usually the better choice when you want live lookup beyond normal order-data retention windows, for example for long warranty periods.
{% endhint %}

## Return Lifecycle Touchpoints

### parcelLab to WMS: register, update, cancel

When a shopper completes a return, parcelLab can notify the retailer-side warehouse flow with the RMA and ASN (advanced shipping notification). This gives the warehouse a pre-advice before the physical parcel arrives.

The same callback layer can also be used later to:

* update the registered return
* add additional labels
* cancel the return before it is closed

### WMS to parcelLab: received-item outcome

After the parcel reaches the warehouse, parcelLab expects the processing result back from the WMS or warehouse middleware. The exact transport can be project-specific, but the business outcome should include the following information:

| Data parcelLab needs from the warehouse                                         | Why it matters                                                                   |
| ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| Return identifier (`rma_reference`, parcelLab return ID, or another stable key) | Correlates the warehouse decision to the correct registered return               |
| Processed timestamp                                                             | Drives auditability, communications, and downstream automation                   |
| Item-level acceptance or rejection result                                       | Determines whether the return is fully accepted, partially accepted, or rejected |
| Accepted and rejected quantities per item                                       | Enables accurate customer communication and financial processing                 |
| Optional refund or deduction information                                        | Allows parcelLab and the retailer to align on the amount that should be refunded |

For documented warehouse-originating updates into parcelLab, see [Warehouse Events for Returns](https://github.com/parcelLab/gitbook-documentation/blob/main/developers/returns/warehouse-events-for-returns/README.md).

### parcelLab to OMS: status updates and refund orchestration

OMS is usually the system of record for order state and refund state. In many implementations parcelLab sends OMS-facing updates at two milestones:

* after drop-off or first return movement, so the order record shows the return is underway
* after warehouse processing, so the OMS can close the return and trigger the final refund

The close/refund callback is documented in the endpoint contract below. Earlier status callbacks are usually project-specific because OMS event models vary by retailer.

## Retailer API Contract

The endpoints below show a common retailer-facing split:

| Endpoint                        | Typically owned by | Purpose                                                 |
| ------------------------------- | ------------------ | ------------------------------------------------------- |
| `GET /orders/{order_reference}` | OMS or middleware  | Live order lookup for the Returns Portal                |
| `POST /rma/register_or_update`  | WMS or middleware  | Create or update the RMA and send the ASN               |
| `POST /rma/cancel`              | WMS or middleware  | Cancel an open return                                   |
| `POST /rma/close`               | OMS or middleware  | Close the return and trigger refund or exchange release |

{% hint style="info" %}
If your OMS and WMS are hidden behind the same middleware service, that is fine. The important part is that the lookup, warehouse, and refund responsibilities remain clearly separated and all POST calls stay idempotent.
{% endhint %}

Across all POST callbacks, `return_registration_id` is the stable parcelLab return UUID. Use it together with `idempotency_key` to deduplicate retries and to correlate warehouse and OMS updates across the full return lifecycle.

### 1. Fetch Order Data

parcelLab requests order data from your system so return eligibility, return-window logic, and line-item selection can be evaluated. This endpoint is most commonly backed by the OMS or a retailer middleware layer.

**Endpoint you provide**

* Method: `GET`
* Example path: `/orders/{order_reference}`

<details>

<summary>Required request input parcelLab sends to your GET endpoint</summary>

| Field             | Type   | Description                 |
| ----------------- | ------ | --------------------------- |
| `order_reference` | string | Shopper-facing order number |

</details>

<details>

<summary>Recommended response fields your GET endpoint should return</summary>

| Field                   | Type           | Why it matters                                  |
| ----------------------- | -------------- | ----------------------------------------------- |
| `order_reference`       | string\*       | Lookup correlation                              |
| `order_id`              | string         | Stable retailer order ID for downstream updates |
| `order_date`            | datetime\*     | Return-window fallback                          |
| `order_shipping_date`   | datetime       | Return-window fallback                          |
| `order_delivery_date`   | datetime       | Primary return-window date                      |
| `currency`              | string\*       | Monetary calculations                           |
| `order_total_amount`    | number\*       | Financial context                               |
| `order_shipping_amount` | number         | Shipping refund/fee logic                       |
| `order_tax_amount`      | number         | Tax-aware calculations                          |
| `customer_email`        | string\*       | Identity and communication                      |
| `customer_phone`        | string         | Optional secondary identity/contact             |
| `customer_address`      | object\*       | Postal verification and return context          |
| `fulfillments`          | array          | Shipment-level status/tracking context          |
| `line_items`            | array\*        | Returnable item data                            |
| `tags`                  | array\[string] | Optional policy segmentation                    |
| `additional_properties` | object         | Optional custom metadata                        |

</details>

<details>

<summary>Recommended fields inside each line item</summary>

| Field                       | Type           | Why it matters                               |
| --------------------------- | -------------- | -------------------------------------------- |
| `line_item_id`              | string\*       | Stable item ID across all lifecycle events   |
| `order_line_id`             | string         | Original order-line reference (if different) |
| `sku`                       | string\*       | Product matching and targeting               |
| `product_id`                | string         | Product-level grouping                       |
| `variant_id`                | string         | Variant-level matching                       |
| `item_name`                 | string\*       | Shopper display                              |
| `item_category`             | string         | Policy targeting                             |
| `item_image_url`            | string\*       | Shopper display                              |
| `ordered_quantity`          | integer\*      | Max returnable quantity                      |
| `already_returned_quantity` | integer        | No longer returnable quantity                |
| `unit_price`                | number\*       | Refund estimate                              |
| `line_tax_amount`           | number         | Tax-aware estimate                           |
| `tags`                      | array\[string] | Optional item-level segmentation             |
| `additional_properties`     | object         | Optional item-level metadata                 |

</details>

<details>

<summary>Sample GET response payload</summary>

```json
{
  "order_reference": "100123",
  "order_id": "ord_9f2ab1",
  "order_date": "2026-01-12T10:15:00Z",
  "order_shipping_date": "2026-01-13T14:05:00Z",
  "order_delivery_date": "2026-01-15T18:40:00Z",
  "currency": "USD",
  "order_total_amount": 149.97,
  "order_shipping_amount": 8.99,
  "order_tax_amount": 12.35,
  "customer_email": "alex@example.com",
  "customer_phone": "+1-555-0100",
  "customer_address": {
    "first_name": "Alex",
    "last_name": "Miller",
    "address_line": "101 Main St",
    "city": "Austin",
    "postal_code": "78701",
    "country_iso3": "USA"
  },
  "fulfillments": [
    {
      "fulfillment_id": "ful_4471",
      "status": "delivered",
      "carrier_code": "dhl",
      "tracking_number": "JD014600006838000000",
      "shipped_date": "2026-01-13",
      "delivered_date": "2026-01-15"
    }
  ],
  "line_items": [
    {
      "line_item_id": "li_001",
      "order_line_id": "ol_001",
      "sku": "HD-001-BLK-M",
      "product_id": "prd_hoodie_001",
      "variant_id": "var_blk_m",
      "item_name": "Everyday Hoodie",
      "item_category": "apparel",
      "item_image_url": "https://cdn.example.com/images/hoodie-black-m.jpg",
      "ordered_quantity": 2,
      "already_returned_quantity": 0,
      "unit_price": 59.99,
      "line_tax_amount": 4.8,
      "tags": ["full-price"],
      "additional_properties": {
        "warehouse": "US-EAST"
      }
    }
  ],
  "tags": ["vip", "online-store"],
  "additional_properties": {
    "sales_channel": "web",
    "loyalty_tier": "gold"
  }
}
```

</details>

### 2. Register or Update RMA (incl. ASN)

parcelLab sends return submission or update payloads so your WMS or middleware can create or update the retailer return request. This call also works as the advanced shipping notification for the warehouse and can be reused if additional labels are issued later.

**Endpoint you provide**

* Method: `POST`
* Example path: `/rma/register_or_update`

<details>

<summary>Required payload sections parcelLab sends to your POST endpoint</summary>

| Section         | Required fields                                                                             |
| --------------- | ------------------------------------------------------------------------------------------- |
| Identity        | `order_reference`, `order_id`, `rma_reference`, `return_registration_id`                    |
| Timing & method | `submitted_at`, `refund_method`                                                             |
| Return lines    | `line_item_id`, `return_quantity`, `return_reason_code`, `reason_note`, `compensation_type` |
| Return labels   | `labels[]` with `carrier_code`, `tracking_number`, `is_free_label`, `label_cost_amount`     |
| Shipping fees   | `refund_shipping_fees`, `shipping_fee_deduction`                                            |
| Refund estimate | `base_amount`, `tax_amount`, `label_cost`, `net_amount`, `final_amount`, `currency`         |
| Metadata        | `tags`, `additional_properties`, `idempotency_key` (same UUID as `return_registration_id`)  |

</details>

<details>

<summary>Sample register/update POST payload</summary>

```json
{
  "order_reference": "100123",
  "order_id": "ord_9f2ab1",
  "rma_reference": "RMA-000042",
  "return_registration_id": "2a8f2c5c-9e54-46de-9ec3-8f9347f7d2b1",
  "submitted_at": "2026-02-24T11:00:00Z",
  "refund_method": "original_payment",
  "refund_shipping_fees": false,
  "line_items": [
    {
      "line_item_id": "li_001",
      "return_quantity": 1,
      "return_reason_code": "size_too_small",
      "reason_note": "Sleeves are too short",
      "compensation_type": "refund"
    }
  ],
  "labels": [
    {
      "carrier_code": "dhl",
      "tracking_number": "JD014600006838000000",
      "is_free_label": false,
      "label_cost_amount": 4.99
    }
  ],
  "shipping_fee_deduction": {
    "mode": "label_cost",
    "amount": 4.99,
    "currency": "USD"
  },
  "refund_estimate": {
    "currency": "USD",
    "base_amount": 59.99,
    "tax_amount": 4.8,
    "label_cost": 4.99,
    "net_amount": 55.0,
    "final_amount": 55.0
  },
  "idempotency_key": "2a8f2c5c-9e54-46de-9ec3-8f9347f7d2b1",
  "tags": ["self-service"],
  "additional_properties": {
    "source": "returns_portal"
  }
}
```

</details>

### 3. Cancel RMA

parcelLab sends cancellation updates when a return is cancelled. This is only possible for returns that are not yet closed.

**Endpoint you provide**

* Method: `POST`
* Example path: `/rma/cancel`

<details>

<summary>Required payload fields parcelLab sends to your cancel POST endpoint</summary>

| Field                    | Required | Description                            |
| ------------------------ | -------- | -------------------------------------- |
| `rma_reference`          | yes      | Return to cancel                       |
| `order_reference`        | yes      | Shopper-facing order number            |
| `order_id`               | yes      | Retailer order ID                      |
| `return_registration_id` | yes      | UUID lifecycle ID from register/update |
| `cancel_reason_code`     | yes      | Structured cancellation reason         |
| `cancel_reason`          | yes      | Human-readable reason                  |
| `cancelled_at`           | yes      | Cancellation timestamp                 |
| `idempotency_key`        | yes      | Same UUID as `return_registration_id`  |
| `tags`                   | no       | Optional segmentation                  |
| `additional_properties`  | no       | Optional metadata                      |

</details>

<details>

<summary>Sample cancel POST payload</summary>

```json
{
  "rma_reference": "RMA-000042",
  "order_reference": "100123",
  "order_id": "ord_9f2ab1",
  "return_registration_id": "2a8f2c5c-9e54-46de-9ec3-8f9347f7d2b1",
  "cancel_reason_code": "rma_expired",
  "cancel_reason": "Return window expired before drop-off",
  "cancelled_at": "2026-02-24T11:15:00Z",
  "idempotency_key": "2a8f2c5c-9e54-46de-9ec3-8f9347f7d2b1",
  "tags": ["cancelled", "expired"],
  "additional_properties": {
    "source": "expiry_job"
  }
}
```

</details>

### 4. Close Return / Trigger Refund

parcelLab sends finalization updates when a return should be closed, meaning the OMS or refund orchestration layer can settle the refund and release any exchange items.

This step is optional if your WMS can issue refunds within your system without an OMS-side close call.

If your WMS calls parcelLab after warehouse receipt instead, use [Process Return Mutations](/docs/developers/returns/process-return-mutations.md).

**Endpoint you provide**

* Method: `POST`
* Example path: `/rma/close`

<details>

<summary>Required payload fields parcelLab sends to your close POST endpoint</summary>

| Field                    | Required | Description                                 |
| ------------------------ | -------- | ------------------------------------------- |
| `rma_reference`          | yes      | Return to close                             |
| `order_reference`        | yes      | Shopper-facing order number                 |
| `order_id`               | yes      | Retailer order ID                           |
| `return_registration_id` | yes      | Same UUID lifecycle ID from register/update |
| `trigger_refund`         | yes      | Finalization refund decision                |
| `release_exchange_items` | yes      | Exchange release/finalization decision      |
| `refund_shipping_fees`   | yes      | Shipping refund decision                    |
| `status_reason`          | yes      | Closing reason                              |
| `idempotency_key`        | yes      | Same UUID as `return_registration_id`       |
| `tags`                   | no       | Optional segmentation                       |
| `additional_properties`  | no       | Optional metadata                           |

</details>

<details>

<summary>Sample close POST payload</summary>

```json
{
  "rma_reference": "RMA-000042",
  "order_reference": "100123",
  "order_id": "ord_9f2ab1",
  "return_registration_id": "2a8f2c5c-9e54-46de-9ec3-8f9347f7d2b1",
  "trigger_refund": true,
  "release_exchange_items": true,
  "refund_shipping_fees": false,
  "status_reason": "warehouse_received",
  "idempotency_key": "2a8f2c5c-9e54-46de-9ec3-8f9347f7d2b1",
  "tags": ["closed", "auto-close"],
  "additional_properties": {
    "close_source": "tracking_event"
  }
}
```

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.parcellab.com/docs/developers/returns/connect-order-data/real-time-api-connection-for-returns.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
