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

# Getting Started

> Core concepts and typical integration workflows for the Return Helper API

<h2 id="prerequisites">
  Before You Integrate
</h2>

Integration responsibility is split between Return Helper and your team. Return Helper provisions credentials and connects your webhook endpoint; your engineering team builds the request signer and the webhook receiver. The two tables below show who owns what, followed by a step-by-step checklist a non-technical project lead can run through with their engineering team.

### Who handles what

| Step                          | Return Helper                                                                                              | Your team                                                                                                             |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| API key and token             | Issued in the User Portal under **Settings → Signing Key and API Token**                                   | Store securely; load into your server config                                                                          |
| Sandbox access                | Sandbox base URLs are documented in [Base URLs](/introduction#base-urls)                                   | Run all integration testing against sandbox first                                                                     |
| Webhook receiver              | Provides the signing key used for signature verification                                                   | Build an HTTPS endpoint, parse the raw body, verify the signature, respond `200` quickly                              |
| Webhook endpoint registration | We activate your endpoint after you submit the setup request form                                          | Submit the [Webhook Setup Request Form](https://forms.gle/iBVkRZvfLQ8o1Nqg8) once your endpoint is publicly reachable |
| Idempotency                   | —                                                                                                          | Deduplicate using `notificationId` (see [Webhooks](/webhooks#event-delivery))                                         |
| Production go-live            | We issue production credentials and switch your registered endpoint to production after sandbox validation | Notify support when sandbox testing is complete and you are ready for production traffic                              |

### Seller checklist

Work through these items in order before calling any state-changing endpoint:

1. **Obtain API credentials.** Log in to the User Portal and copy the API key and API token from **Settings → Signing Key and API Token**. The same screen shows the **signing key** used to verify webhook signatures.
2. **Decide your environment.** Start in sandbox (UAT). Production base URLs are only used after sandbox validation — see [Base URLs](/introduction#base-urls).
3. **Build your webhook receiver.** Stand up an HTTPS endpoint that parses the raw POST body, verifies the `returnhelper-signature` header using the signing key, deduplicates on `notificationId`, and responds `200 OK` quickly. Reference code is in [Webhooks → Signature Verification](/webhooks#signature-verification).
4. **Register your endpoint with us.** Submit the [Webhook Setup Request Form](https://forms.gle/iBVkRZvfLQ8o1Nqg8) once the endpoint is reachable from the public internet. We complete the connection — there is no self-serve registration API today.
5. **Test end-to-end in sandbox.** Walk through label creation, warehouse arrival, and post-arrival handling using the flows described in the rest of this guide. Confirm the corresponding webhook events arrive at your receiver.
6. **Request production go-live.** When sandbox testing is complete, contact support to swap your credentials and registered endpoint to production.

<Note>
  Until step 4 is complete, label results and warehouse events have nowhere to go. Without a registered webhook endpoint the API will still accept requests, but you cannot retrieve generated labels or learn when shipments arrive.
</Note>

## Return Flow Overview

A typical return has three stages:

1. **Before warehouse arrival** — Create a return shipment and receive a shipping label.
2. **Warehouse arrival** — The package is scanned in; images are uploaded; the shipment becomes a Return Inventory record.
3. **Post-arrival handling** — Instruct the warehouse how to handle the inventory (dispose, resend, recall, VAS, etc.).

***

## End-to-End Recipes

Three compact recipes that map each lifecycle moment to the exact API call you make, the webhook event you listen for, and the next action you take. Each recipe links to the prose section below for the full explanation.

### Recipe 1 — Create a return label

| Step        | What you do                                     | Webhook (`action`)                                     | Next action                                                                                                                                |
| ----------- | ----------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| 1           | `POST /api/ReturnShipment/createReturnShipment` | —                                                      | Read `shipmentId` and `labelRequestStatusCode: queued` from the synchronous response.                                                      |
| 2 (success) | (wait)                                          | `labelGenerated`                                       | Read `labelUrl` and `trackingNumber` from the webhook payload; deliver the label to the customer. Match using `shipmentId`, not `labelId`. |
| 2 (failure) | (wait)                                          | `labelGenerated` with `labelRequestStatusCode: failed` | Inspect `failReasons` and `errorMessages`; surface the failure to your CS / ops team.                                                      |

Detailed flow: [Requesting a Return Label](#requesting-a-return-label).

### Recipe 2 — Receive a warehouse arrival

No outbound API call needed — wait for the warehouse to report the events.

| Step                       | Webhook (`action`)                                                                                             | Next action                                                                                                                                              |
| -------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1                          | `markShipmentArrive`                                                                                           | Match by `shipmentId` to the Return Shipment you created earlier.                                                                                        |
| 2                          | `newInventoryCreated` — one event per resulting Return Inventory (a single shipment can produce more than one) | Store the new `returnInventoryId` against the matching shipment in your system.                                                                          |
| 3                          | `changeLineItemImage` whenever the warehouse adds or replaces an image                                         | Refresh the cached image URL list for that `returnInventoryId`.                                                                                          |
| Variant — Unknown Shipment | `assignUnknown` arrives instead of steps 1+2 when a parcel turns up without a seller-created Return Shipment   | Treat as a brand-new Return Inventory; the payload already contains `returnInventoryId`, `shipmentId`, `returnRequestId`, and any pre-assignment images. |

Detailed flow: [Return Inventory at Warehouse Arrival](#return-inventory-at-warehouse-arrival).

### Recipe 3 — Send a handling instruction

Pick the row that matches the operation you want; the API call and the webhook to wait for are different for each.

| Operation         | API call                                                                                            | Webhook (`action`)                                                                      | Next action                                                                                                                        |
| ----------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Dispose / On-hold | `POST /api/ReturnInventory/UpdateReturnInventoryHandling` with the dispose or on-hold handling code | `completeInventoryHandling`                                                             | Inventory closed; no further action needed.                                                                                        |
| Resend            | `POST /api/Resend/createResend` referencing one or more `returnInventoryId`                         | `updateResendStatus`                                                                    | Track the resend's outbound shipment until delivered to the buyer.                                                                 |
| Recall            | `POST /api/Recall/createRecallByReturnInventoryId` with up to 100 `returnInventoryId`               | `recallUpdateStatus`                                                                    | Track the shipment until the inventory arrives at the Hong Kong consolidation warehouse.                                           |
| VAS               | `POST /api/Vas/CreateByReturnInventoryId` with the `returnInventoryId` and the VAS types you want   | `vasUpdated` (and `splitLineItem` if the VAS splits the inventory into multiple pieces) | Re-read the inventory record. If the VAS produced a split, each new piece arrives as its own `returnInventoryId` with its own RMA. |

To withdraw a handling instruction before it is processed, call the cancel endpoint for the same operation (e.g. `POST /api/ReturnInventory/CancelReturnInventoryHandling`).

Detailed flow: [Handling Instructions](#handling-instructions).

***

## Requesting a Return Label

Label creation is **asynchronous**. The flow is:

1. Call [**Create Return Shipment**](/api-reference/returnshipment/create-return-shipment) to create a return shipment record and queue a label request.
2. Return Helper generates the label and delivers the result to your webhook notification endpoint via the [**label** notification event](/webhooks#label-result).

You must have a webhook endpoint registered to receive label results. Without it, you will have no way to retrieve the generated label.

```mermaid theme={null}
sequenceDiagram
    participant S as Seller System
    participant RH as Return Helper (RH)
    participant W as Seller Webhook Endpoint

    S->>RH: createReturnShipment(request)
    RH->>RH: Validate request
    alt No validation error
        RH-->>S: 200 OK (request submitted successfully)
        RH->>RH: Queue label generation process
        RH->>W: POST /label-notification (result payload)
        Note over W: [Label generation success]<br/>Payload includes labelUrl
        Note over W: [Label generation failed]<br/>Payload includes failReasons + errorMessages
    else Validation error
        RH-->>S: 4xx Error (validation error messages)
    end
```

***

## RMA (Return Merchandise Authorization)

When a shipment enters a Return Helper warehouse it is assigned a globally unique RMA. Return Helper uses RMA as the primary communication identifier instead of the carrier tracking number, for two reasons:

* Tracking numbers can be duplicated across carriers, or even within the same carrier.
* When a parcel is split via VAS, each resulting parcel receives its own RMA.

**Normal RMA format:**

```
<warehouse prefix>-<warehouse ID>-<YYMMDD>-<env letter><sequence up to 5 digits>-<check digits>
```

Example: `TWN-20-230101-D12345-36`

**Split RMA format** (after a VAS split):

```
<warehouse prefix>-<warehouse ID>-<YYMMDD>-<env letter><sequence up to 5 digits>-<split sequence 2 digits>-<check digits>
```

Example: `TWN-20-230101-D12345-01-36`

***

## Return Inventory at Warehouse Arrival

When a return shipment arrives at the warehouse, it is marked received and converted into one or more **Return Inventory** records, each with a unique `returnInventoryId`.

### Type 1 — Seller-initiated shipment

1. Seller created the shipment via the API and provided a label.
2. Warehouse marks it received → [**warehouseMarkShipmentArrivedV2**](/webhooks#warehouse-shipment-arrived-v2) webhook is sent, followed by [**inventoryCreated**](/webhooks#inventory-created) (which includes `returnInventoryId`).
3. If a single label covers multiple packages, each package becomes a separate Return Inventory record sharing the same `shipmentId` and `returnRequestId`. One [**inventoryCreated**](/webhooks#inventory-created) event is sent per inventory.
4. Inventory images are uploaded next and delivered via [**changeLineItemImage**](/webhooks#image-updated).

### Type 2 — Unknown shipment assigned to seller

1. The shipment arrived without a seller-created record but was identified as belonging to a seller.
2. [**assignUnknown**](/webhooks#unknown-shipment-assigned) webhook is sent, including the return inventory payload, `returnInventoryId`, `shipmentId`, and `returnRequestId`.
3. Multiple [**inventoryCreated**](/webhooks#inventory-created) events may follow if the package contains multiple items.
4. Images captured before assignment are included in [**assignUnknown**](/webhooks#unknown-shipment-assigned); any subsequent changes arrive via [**changeLineItemImage**](/webhooks#image-updated).

***

## Inventory Images

When images are uploaded (or the image list changes), the [**changeLineItemImage**](/webhooks#image-updated) webhook is sent containing the image URL list.

***

## Handling Instructions

Once a Return Inventory record exists, instruct the warehouse what to do with it:

### Dispose

Call [**Update Return Inventory Handling**](/api-reference/returninventory/update-return-inventory-handling) with a dispose handling type. Use [**Cancel Return Inventory Handling**](/api-reference/returninventory/cancel-return-inventory-handling) to withdraw the instruction.

### On-hold

Call [**Update Return Inventory Handling**](/api-reference/returninventory/update-return-inventory-handling) with an on-hold handling type.

### Resend

1. Call [**Create Resend**](/api-reference/resend/create-resend-order) with a list of `returnInventoryId` values.
2. Receive the resend tracking number via the [**resend**](/webhooks#resend-status-update) webhook notification.
3. Call [**Cancel Resend**](/api-reference/resend/cancel-resend-order) if the resend is no longer needed.

### Recall

1. Call [**Create Recall by Return Inventory IDs**](/api-reference/recall/create-recall-by-return-inventory-ids) with up to 100 `returnInventoryId` values.
2. Tracking updates and pick-up status changes are delivered via the [**recall**](/webhooks#recall-status-update) webhook notification.

### Value-Added Services (VAS)

1. Call [**Create VAS**](/api-reference/vas/create-vas-by-return-inventory-id) with the `returnInventoryId` and the required VAS types.
2. Results are delivered via the [**UpdateVas**](/webhooks#vas-update) webhook notification.

***

## Custom Fields

Custom fields let you attach arbitrary key-value metadata to a return. They are stored but not processed by Return Helper — they are returned to you in relevant webhook notifications.

* Type: `Dictionary<string, string>`
* Maximum 24 custom fields per return.

```json theme={null}
{
  "customFieldMap": {
    "customerId": "buyer123",
    "dateOfPurchase": "2024-07-01"
  }
}
```

Custom fields are available in [**Create Return Shipment**](/api-reference/returnshipment/create-return-shipment) and are echoed back in the [**warehouseMarkShipmentArrivedV2**](/webhooks#warehouse-shipment-arrived-v2) notification.

***

## FBA (Fulfilled by Amazon) Returns

Customers can send FBA products to a Return Helper warehouse for processing (restock, replenish, recall, dispose, etc.).

**Typical FBA workflow:**

1. Call [**Create FBA Shipment**](/api-reference/fbashipment/create-fba-shipment) to notify Return Helper and send the products to the warehouse.
2. The shipment is received, put away as FBA inventory with `fnsku` and `quantity`, and delivered via webhook.
3. Check existing FBA inventory with [**Get FBA Warehouse Inventory List**](/api-reference/fbawarehouseinventory/get-fba-warehouse-inventory-list-by-fnsku).
4. Create instructions via [**Create FBA Instructions**](/api-reference/fbainstruction/create-fba-instructions) (replenishment requires additional shipping information not currently available in the API).
5. Return Helper processes the instruction and notifies you of results via webhook.
6. Check instruction status via the relevant Get FBA Instruction Detail endpoint (Recall, Dispose, Restock, Others).

**Retrieving historical FBA data** (for existing portal users migrating to the API):

1. Use [**List FBA Shipments**](/api-reference/fbashipment/list-fba-shipments-with-pagination) to retrieve past shipments within a date range, collecting `fbaShipmentId` values.
2. Call [**Get FBA Shipment Item List**](/api-reference/fbashipmentitem/get-items-in-fba-shipment) to get items, FNSKU, and quantities per shipment.
3. Use [**Get FBA Warehouse Inventory List**](/api-reference/fbawarehouseinventory/get-fba-warehouse-inventory-list-by-fnsku) with an FNSKU to see current inventory.
4. Use [**List FBA Instructions**](/api-reference/fbainstruction/list-fba-instructions-with-pagination) to find past instructions.
5. Use [**Get FBA Instruction Item List**](/api-reference/fbainstructionitem/get-items-in-fba-instruction) per instruction for line-item detail.

Once you have retrieved historical data, rely on regular API calls and webhook events going forward rather than polling.

***

## Retrieving Historical Data

<Note>
  This section is for existing Return Helper Portal users who are migrating to the API. If you are integrating from scratch, all necessary data is exchanged through normal API calls and webhook events — you do not need to retrieve historical data.
</Note>

**Retrieving historical return shipment data:**

Use [**List Shipments**](/api-reference/shipment/list-shipments-with-pagination) to retrieve past return shipments within a date range.

**Retrieving historical return inventory data:**

Use [**List Return Inventories**](/api-reference/returninventory/list-return-inventories-with-pagination) to retrieve past return inventory records within a date range.

For FBA historical data, see the **Retrieving historical FBA data** section above.

Once you have retrieved all historical data, rely on regular API calls and webhook events going forward rather than continuously polling for history data.

***

## Response Structure

Every API response contains a `meta` object indicating the result status.

**Successful response (`status: 200`):**

```json theme={null}
{
  "apiBalances": [
    {
      "apiBalanceId": 7,
      "currencyCode": "usd",
      "balance": 2044.233
    }
  ],
  "correlationId": "0HM9VIKSKH2CB:00000002",
  "meta": {
    "status": 200,
    "data": {},
    "errorCode": null,
    "error": {}
  },
  "totalNumberOfRecords": 1
}
```

**Failed response (e.g. invalid `warehouseId`):**

```json theme={null}
{
  "correlationId": "0HM9VIKSKH2CF:00000002",
  "meta": {
    "status": 400,
    "data": {},
    "errorCode": "VALIDATION_FAILED",
    "error": {
      "warehouseId": "The value 'invalid' is not valid."
    }
  }
}
```

Any `status` value other than `200` means the request did not complete successfully. The `errorCode` and `error` fields provide details.
