メインコンテンツへスキップ
GET
/
api
/
ReturnInventory
/
list
List return inventories with pagination
curl --request GET \
  --url https://api.returnshelper.com/uat/user/api/ReturnInventory/list \
  --header 'x-rr-apikey: <api-key>' \
  --header 'x-rr-apitoken: <api-key>'
{
  "data": [
    {
      "returnInventoryId": 123,
      "returnRequestId": 123,
      "returnRequestLineItemId": "<string>",
      "rma": "<string>",
      "itemRma": "<string>",
      "sku": "<string>",
      "handlingCode": "<string>",
      "handlingStatusCode": "<string>",
      "warehouseId": 123,
      "createOn": "2023-11-07T05:31:56Z"
    }
  ],
  "totalNumberOfRecords": 123
}
本エンドポイントは返品在庫の状態を追跡する方法として 推奨されません。Return Helper API における在庫ライフサイクルの真実のソースは Webhook イベントストリーム で、markShipmentArrivenewInventoryCreatedvasUpdated、在庫ハンドリング完了イベント、notifyUserRmaSwapped などが状態変更のたびにエンドポイントへ配信されます。統合は webhook を中心に構築してください。本リストエンドポイントは一回限りのバックフィルおよびオペレーション照合のためだけに用意されています。
返品在庫レコードのページング付き一覧——倉庫側のアイテム単位の状態——を返します。各レコードは、現在のハンドリング決定、RMA、SKU マッピング、倉庫割当を含む 1 件の受領アイテムを表します。

呼び出してよいタイミング(それ以外では呼ばないでください)

  • 一回限りのバックフィル — 初回統合時、webhook 購読の前にローカル DB に既存の在庫を書き込むため。
  • 定期的な整合性チェック — webhook 配信の漏れや順序ずれを検知するため。ローカルキャッシュとこのエンドポイントの結果を差分してください。
継続的な状態(パーセルがログされた、ハンドリングが完了した、RMA が再割当された など)には webhook を購読してください。本エンドポイントを状態変更検知のためポーリングする運用はサポートされず、高負荷時には古いデータを返します。

必須パラメータ

  • createFrom / createTo — どちらも必須、ISO 8601 タイムスタンプ。範囲の上限は 62 日SearchConfig.simpleRecordsMaxDays)。それ以上はソフトエラーで拒否されます。「62 日」の正確な意味は下の ウィンドウのセマンティクス を参照してください。
  • pageSize1 から 50 の間。
  • offset — 非負整数。pageSize と組み合わせてオフセットページングを行います。

レスポンスの注意

  • totalNumberOfRecordsdata と同じ階層のトップレベルフィールド)が現在のウィンドウの総件数です——ページングループの終了条件として使用してください。
  • handlingCode は当該アイテムの現在のハンドリング決定を表します——変更するには 返品在庫ハンドリングを更新 を呼び出してください。
  • handlingStatusCode はそのハンドリングの状態を表します。すべてのハンドリングステータスを取得 で変換できます。
  • アイテムの RMA(rma)は倉庫が割り当てた識別子で、セラー側の参照番号ではありません。

履歴在庫のバックフィル

本エンドポイントを使って、過去に発生したすべての返品在庫レコードをローカル DB に取り込み、その後は webhook で継続的に更新します。API は 1 リクエストあたり最長 62 日に制限されているため、タイムラインを 62 日ウィンドウで遡り、各ウィンドウ内でページングを行い、アカウントの開設日まで進みます。

ウィンドウのセマンティクス

ループを書き始める前に、以下 2 つのルールを把握しておいてください——これがクリーンなバックフィルと「気づかぬうちに 1 日漏らす」バックフィルの境目です。
  1. バリデータの規則(日単位の差):
    createTo.Date − createFrom.Date  ≤  62
    
    比較前に時刻部分は切り落とされます。よって createFrom = 2024-03-13T15:00:00ZcreateTo = 2024-05-14T09:00:00Z のリクエストは有効です(May 14 − Mar 13 = 62 日)。実時刻差が 62 × 24 時間より短くても問題ありません。
  2. データのフィルタ(両端の日付を丸ごと含む):
    createOn ≥ createFrom.BeginOfDay()   AND   createOn ≤ createTo.EndOfDay()
    
    つまりサーバ側は createFrom を当日 00:00:00.000 に、createTo を当日 23:59:59.999 に拡張してからフィルタを適用します。したがって、1 回の有効なリクエストは連続する 63 日分のデータをカバーします(createFrom の日付の全日、createTo の日付の全日、およびその間のすべての日)。
スライディングウィンドウ・バックフィルへの実務的な影響: ウィンドウ N の createFrom をそのままウィンドウ N+1 の createTo として使うと、その境界日が両方の結果に現れます。これは 重複 であって 欠落 ではありません——アルゴリズムが行を漏らすことは決してなく、各ウィンドウの継ぎ目で約 1 日分を多めに取得するだけです。ローカル ストアが returnInventoryId を主キーとし UPSERT(または INSERT IGNORE)で書き込む限り、重複は自動的に解決され最終状態は完全に正確になります。 完全に重複なしで取得したい場合は、毎回 windowEnd = windowStart ではなく windowEnd = windowStart − 1 day に進めてください。各ウィンドウが重なりなく 63 日ぴったりのスライスになります。どちらの実装も正しいですが、下記のサンプルはクライアント/サーバ間の時計ずれに寛容な「継ぎ目を許容する」版を推奨デフォルトとして採用しています。

バックフィルのアルゴリズム

  1. historyStart を決める(例: アカウント開設日)。
  2. windowEnd = now() から開始。
  3. windowStart = max(windowEnd − 62 日, historyStart) を計算。
  4. ウィンドウ内で offset = 0 から pageSize 単位でページングし、offset ≥ totalNumberOfRecords になるまで続ける。各レコードを returnInventoryId を主キーとしてローカル DB に UPSERT する。
  5. windowEnd = windowStart にして手順 3 へ戻り、windowEnd ≤ historyStart になるまで繰り返す。
  6. 以降は newInventoryCreated webhook(およびその他の在庫ライフサイクル イベント)でローカル ストアを維持。webhook のデータ欠落が疑われない限り、再バックフィルは不要です。

サンプルコード

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Instant;
import java.time.temporal.ChronoUnit;

// Requires a JSON library on the classpath. Below uses org.json for brevity:
//   <dependency><groupId>org.json</groupId><artifactId>json</artifactId></dependency>
import org.json.JSONArray;
import org.json.JSONObject;

class Main {
  static final String BASE_URL  = "https://api.returnhelpercentre.com/v1/user"; // production
  // sandbox: "https://api.returnshelper.com/uat/user"
  static final String API_KEY   = "<your api key>";
  static final String API_TOKEN = "<your api token>";

  static final int PAGE_SIZE   = 50;
  static final int WINDOW_DAYS = 62; // server cap: createTo.Date - createFrom.Date <= 62

  public static void main(String[] args) throws Exception {
    Instant historyStart = Instant.parse("2024-01-01T00:00:00Z"); // backfill anchor
    Instant windowEnd    = Instant.now();                         // walk backwards from now

    HttpClient http = HttpClient.newHttpClient();

    while (windowEnd.isAfter(historyStart)) {
      Instant windowStart = windowEnd.minus(WINDOW_DAYS, ChronoUnit.DAYS);
      if (windowStart.isBefore(historyStart)) {
        windowStart = historyStart;
      }

      int offset = 0;
      int total  = Integer.MAX_VALUE;

      while (offset < total) {
        String url = BASE_URL + "/api/ReturnInventory/list"
                   + "?pageSize="   + PAGE_SIZE
                   + "&offset="     + offset
                   + "&createFrom=" + windowStart
                   + "&createTo="   + windowEnd;

        HttpRequest req = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .header("x-rr-apikey",   API_KEY)
            .header("x-rr-apitoken", API_TOKEN)
            .header("Accept",        "application/json")
            .GET()
            .build();

        HttpResponse<String> resp = http.send(req, HttpResponse.BodyHandlers.ofString());
        JSONObject body = new JSONObject(resp.body());

        // Standard envelope: business status is in meta.status, not HTTP status.
        JSONObject meta = body.optJSONObject("meta");
        if (meta == null || meta.optInt("status") != 200) {
          System.err.println("list call failed: " + (meta == null ? "no meta" : meta.toString()));
          return;
        }

        total = body.optInt("totalNumberOfRecords", 0);
        JSONArray rows = body.optJSONArray("data");
        if (rows != null) {
          for (int i = 0; i < rows.length(); i++) {
            JSONObject inv = rows.getJSONObject(i);
            // TODO: UPSERT into your DB with returnInventoryId as primary key.
            //       Adjacent windows share a seam day, so the same row may be
            //       returned twice; UPSERT absorbs the duplicate.
            //   inv.getLong("returnInventoryId")
            //   inv.getString("handlingCode")
            //   inv.getString("handlingStatusCode")
            //   inv.getInt("warehouseId")
          }
        }

        offset += PAGE_SIZE;
        Thread.sleep(200); // light throttle
      }

      windowEnd = windowStart;
    }
  }
}
API のエラーレスポンスの解釈と処理については Error codes を参照してください。

承認

x-rr-apikey
string
header
必須

Your API key

x-rr-apitoken
string
header
必須

Your API token — keep this private

クエリパラメータ

pageSize
integer
必須

Number of records per page (1–50)

必須範囲: 1 <= x <= 50
offset
integer
必須
createFrom
string<date-time>
必須
createTo
string<date-time>
必須

レスポンス

Success

data
object[]

List of return inventories

totalNumberOfRecords
integer<int32>

Total count of return inventories