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>'import requests
url = "https://api.returnshelper.com/uat/user/api/ReturnInventory/list"
headers = {
"x-rr-apikey": "<api-key>",
"x-rr-apitoken": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'x-rr-apikey': '<api-key>', 'x-rr-apitoken': '<api-key>'}
};
fetch('https://api.returnshelper.com/uat/user/api/ReturnInventory/list', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.returnshelper.com/uat/user/api/ReturnInventory/list",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-rr-apikey: <api-key>",
"x-rr-apitoken: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.returnshelper.com/uat/user/api/ReturnInventory/list"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-rr-apikey", "<api-key>")
req.Header.Add("x-rr-apitoken", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.returnshelper.com/uat/user/api/ReturnInventory/list")
.header("x-rr-apikey", "<api-key>")
.header("x-rr-apitoken", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.returnshelper.com/uat/user/api/ReturnInventory/list")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-rr-apikey"] = '<api-key>'
request["x-rr-apitoken"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"returnInventoryId": 123,
"returnRequestId": 123,
"returnRequestLineItemId": "<string>",
"rma": "<string>",
"itemRma": "<string>",
"sku": "<string>",
"handlingCode": "<string>",
"handlingStatusCode": "<string>",
"warehouseId": 123
}
],
"totalNumberOfRecords": 123
}{
"correlationId": "<string>",
"meta": {
"status": 123,
"data": {},
"errorCode": "<string>",
"error": {}
}
}返品在庫
Return Inventories 一覧(ページネーション付き)
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>'import requests
url = "https://api.returnshelper.com/uat/user/api/ReturnInventory/list"
headers = {
"x-rr-apikey": "<api-key>",
"x-rr-apitoken": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'x-rr-apikey': '<api-key>', 'x-rr-apitoken': '<api-key>'}
};
fetch('https://api.returnshelper.com/uat/user/api/ReturnInventory/list', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.returnshelper.com/uat/user/api/ReturnInventory/list",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-rr-apikey: <api-key>",
"x-rr-apitoken: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.returnshelper.com/uat/user/api/ReturnInventory/list"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-rr-apikey", "<api-key>")
req.Header.Add("x-rr-apitoken", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.returnshelper.com/uat/user/api/ReturnInventory/list")
.header("x-rr-apikey", "<api-key>")
.header("x-rr-apitoken", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.returnshelper.com/uat/user/api/ReturnInventory/list")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-rr-apikey"] = '<api-key>'
request["x-rr-apitoken"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"returnInventoryId": 123,
"returnRequestId": 123,
"returnRequestLineItemId": "<string>",
"rma": "<string>",
"itemRma": "<string>",
"sku": "<string>",
"handlingCode": "<string>",
"handlingStatusCode": "<string>",
"warehouseId": 123
}
],
"totalNumberOfRecords": 123
}{
"correlationId": "<string>",
"meta": {
"status": 123,
"data": {},
"errorCode": "<string>",
"error": {}
}
}本エンドポイントは返品在庫の状態を追跡する方法として 推奨されません。Return Helper API における在庫ライフサイクルの真実のソースは Webhook イベントストリーム で、
markShipmentArrive、newInventoryCreated、vasUpdated、在庫ハンドリング完了イベント、notifyUserRmaSwapped などが状態変更のたびにエンドポイントへ配信されます。統合は webhook を中心に構築してください。本リストエンドポイントは一回限りのバックフィルおよびオペレーション照合のためだけに用意されています。呼び出してよいタイミング(それ以外では呼ばないでください)
- 一回限りのバックフィル — 初回統合時、webhook 購読の前にローカル DB に既存の在庫を書き込むため。
- 定期的な整合性チェック — webhook 配信の漏れや順序ずれを検知するため。ローカルキャッシュとこのエンドポイントの結果を差分してください。
必須パラメータ
createFrom/createTo— どちらも必須、ISO 8601 タイムスタンプ。範囲の上限は 62 日(SearchConfig.simpleRecordsMaxDays)。それ以上はソフトエラーで拒否されます。「62 日」の正確な意味は下の ウィンドウのセマンティクス を参照してください。pageSize—1から50の間。offset— 非負整数。pageSizeと組み合わせてオフセットページングを行います。
レスポンスの注意
totalNumberOfRecords(dataと同じ階層のトップレベルフィールド)が現在のウィンドウの総件数です——ページングループの終了条件として使用してください。handlingCodeは当該アイテムの現在のハンドリング決定を表します——変更するには 返品在庫ハンドリングを更新 を呼び出してください。handlingStatusCodeはそのハンドリングの状態を表します。すべてのハンドリングステータスを取得 で変換できます。- アイテムの RMA(
rma)は倉庫が割り当てた識別子で、セラー側の参照番号ではありません。
履歴在庫のバックフィル
本エンドポイントを使って、過去に発生したすべての返品在庫レコードをローカル DB に取り込み、その後は webhook で継続的に更新します。API は 1 リクエストあたり最長 62 日に制限されているため、タイムラインを 62 日ウィンドウで遡り、各ウィンドウ内でページングを行い、アカウントの開設日まで進みます。ウィンドウのセマンティクス
ループを書き始める前に、以下 2 つのルールを把握しておいてください——これがクリーンなバックフィルと「気づかぬうちに 1 日漏らす」バックフィルの境目です。-
バリデータの規則(日単位の差):
比較前に時刻部分は切り落とされます。よって
createTo.Date − createFrom.Date ≤ 62createFrom = 2024-03-13T15:00:00Z、createTo = 2024-05-14T09:00:00Zのリクエストは有効です(May 14 − Mar 13 = 62日)。実時刻差が 62 × 24 時間より短くても問題ありません。 -
データのフィルタ(両端の日付を丸ごと含む):
つまりサーバ側は
`createFrom` の開始から `createTo` の終了までに作成されたレコードcreateFromを当日00:00:00.000に、createToを当日23:59:59.999に拡張してからフィルタを適用します。したがって、1 回の有効なリクエストは連続する 63 日分のデータをカバーします(createFrom の日付の全日、createTo の日付の全日、およびその間のすべての日)。
createFrom をそのままウィンドウ N+1 の createTo として使うと、その境界日が両方の結果に現れます。これは 重複 であって 欠落 ではありません——アルゴリズムが行を漏らすことは決してなく、各ウィンドウの継ぎ目で約 1 日分を多めに取得するだけです。ローカル ストアが returnInventoryId を主キーとし UPSERT(または INSERT IGNORE)で書き込む限り、重複は自動的に解決され最終状態は完全に正確になります。
完全に重複なしで取得したい場合は、毎回 windowEnd = windowStart ではなく windowEnd = windowStart − 1 day に進めてください。各ウィンドウが重なりなく 63 日ぴったりのスライスになります。どちらの実装も正しいですが、下記のサンプルはクライアント/サーバ間の時計ずれに寛容な「継ぎ目を許容する」版を推奨デフォルトとして採用しています。
バックフィルのアルゴリズム
historyStartを決める(例: アカウント開設日)。windowEnd = now()から開始。windowStart = max(windowEnd − 62 日, historyStart)を計算。- ウィンドウ内で
offset = 0からpageSize単位でページングし、offset ≥ totalNumberOfRecordsになるまで続ける。各レコードをreturnInventoryIdを主キーとしてローカル DB に UPSERT する。 windowEnd = windowStartにして手順 3 へ戻り、windowEnd ≤ historyStartになるまで繰り返す。- 以降は
newInventoryCreatedwebhook(およびその他の在庫ライフサイクル イベント)でローカル ストアを維持。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;
}
}
}
// Requires Node.js 18+ for built-in fetch.
const BASE_URL = 'https://api.returnhelpercentre.com/v1/user'; // production
// sandbox: 'https://api.returnshelper.com/uat/user'
const API_KEY = '<your api key>';
const API_TOKEN = '<your api token>';
const PAGE_SIZE = 50;
const WINDOW_DAYS = 62; // server cap: createTo.Date - createFrom.Date <= 62
const MS_PER_DAY = 24 * 60 * 60 * 1000;
async function main() {
const historyStart = new Date('2024-01-01T00:00:00Z'); // backfill anchor
let windowEnd = new Date(); // walk backwards from now
while (windowEnd > historyStart) {
let windowStart = new Date(windowEnd.getTime() - WINDOW_DAYS * MS_PER_DAY);
if (windowStart < historyStart) {
windowStart = historyStart;
}
let offset = 0;
let total = Infinity;
while (offset < total) {
const params = new URLSearchParams({
pageSize: String(PAGE_SIZE),
offset: String(offset),
createFrom: windowStart.toISOString(),
createTo: windowEnd.toISOString(),
});
const resp = await fetch(`${BASE_URL}/api/ReturnInventory/list?${params}`, {
headers: {
'x-rr-apikey': API_KEY,
'x-rr-apitoken': API_TOKEN,
'Accept': 'application/json',
},
});
const body = await resp.json();
// Standard envelope: business status is in meta.status, not HTTP status.
if (body?.meta?.status !== 200) {
console.error('list call failed:', body?.meta);
return;
}
total = body.totalNumberOfRecords ?? 0;
const rows = body.data ?? [];
for (const inv of rows) {
// 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.returnInventoryId
// inv.handlingCode
// inv.handlingStatusCode
// inv.warehouseId
}
offset += PAGE_SIZE;
await new Promise((r) => setTimeout(r, 200)); // light throttle
}
windowEnd = windowStart;
}
}
main().catch(console.error);
// Requires Node.js 18+ for built-in fetch (or a fetch polyfill in older runtimes).
const BASE_URL = 'https://api.returnhelpercentre.com/v1/user'; // production
// sandbox: 'https://api.returnshelper.com/uat/user'
const API_KEY = '<your api key>';
const API_TOKEN = '<your api token>';
const PAGE_SIZE = 50;
const WINDOW_DAYS = 62; // server cap: createTo.Date - createFrom.Date <= 62
const MS_PER_DAY = 24 * 60 * 60 * 1000;
interface ApiEnvelope<T> {
correlationId: string;
meta: {
status: number;
errorCode?: string | null;
error?: Record<string, unknown>;
};
data?: T[];
totalNumberOfRecords?: number;
}
interface ReturnInventoryRow {
returnInventoryId: number;
handlingCode: string;
handlingStatusCode: string;
warehouseId: number;
// ...other fields documented in the API reference
}
async function main(): Promise<void> {
const historyStart = new Date('2024-01-01T00:00:00Z'); // backfill anchor
let windowEnd = new Date(); // walk backwards from now
while (windowEnd > historyStart) {
let windowStart = new Date(windowEnd.getTime() - WINDOW_DAYS * MS_PER_DAY);
if (windowStart < historyStart) {
windowStart = historyStart;
}
let offset = 0;
let total = Infinity;
while (offset < total) {
const params = new URLSearchParams({
pageSize: String(PAGE_SIZE),
offset: String(offset),
createFrom: windowStart.toISOString(),
createTo: windowEnd.toISOString(),
});
const resp = await fetch(`${BASE_URL}/api/ReturnInventory/list?${params}`, {
headers: {
'x-rr-apikey': API_KEY,
'x-rr-apitoken': API_TOKEN,
'Accept': 'application/json',
},
});
const body = (await resp.json()) as ApiEnvelope<ReturnInventoryRow>;
// Standard envelope: business status is in meta.status, not HTTP status.
if (body.meta?.status !== 200) {
console.error('list call failed:', body.meta);
return;
}
total = body.totalNumberOfRecords ?? 0;
const rows = body.data ?? [];
for (const inv of rows) {
// 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.returnInventoryId
// inv.handlingCode
// inv.handlingStatusCode
// inv.warehouseId
}
offset += PAGE_SIZE;
await new Promise((r) => setTimeout(r, 200)); // light throttle
}
windowEnd = windowStart;
}
}
main().catch(console.error);
// Salesforce Apex — callable from an execute-anonymous window or wrapped in a
// Queueable for large backfills (single-transaction callout limit is 100).
//
// Add the API host to "Remote Site Settings" before running.
public class Main {
private static final String BASE_URL = 'https://api.returnhelpercentre.com/v1/user'; // production
// sandbox: 'https://api.returnshelper.com/uat/user'
private static final String API_KEY = '<your api key>';
private static final String API_TOKEN = '<your api token>';
private static final Integer PAGE_SIZE = 50;
private static final Integer WINDOW_DAYS = 62; // server cap: createTo.Date - createFrom.Date <= 62
public static void main() {
Datetime historyStart = Datetime.newInstanceGmt(2024, 1, 1, 0, 0, 0); // backfill anchor
Datetime windowEnd = Datetime.now(); // walk backwards from now
Http http = new Http();
while (windowEnd > historyStart) {
Datetime windowStart = windowEnd.addDays(-WINDOW_DAYS);
if (windowStart < historyStart) {
windowStart = historyStart;
}
Integer offset = 0;
Integer total = Integer.MAX_VALUE;
while (offset < total) {
String url = BASE_URL + '/api/ReturnInventory/list'
+ '?pageSize=' + PAGE_SIZE
+ '&offset=' + offset
+ '&createFrom=' + EncodingUtil.urlEncode(formatGmt(windowStart), 'UTF-8')
+ '&createTo=' + EncodingUtil.urlEncode(formatGmt(windowEnd), 'UTF-8');
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setEndpoint(url);
req.setHeader('x-rr-apikey', API_KEY);
req.setHeader('x-rr-apitoken', API_TOKEN);
req.setHeader('Accept', 'application/json');
HttpResponse resp = http.send(req);
Map<String, Object> body = (Map<String, Object>) JSON.deserializeUntyped(resp.getBody());
Map<String, Object> meta = (Map<String, Object>) body.get('meta');
// Standard envelope: business status is in meta.status, not HTTP status.
if (meta == null || (Integer) meta.get('status') != 200) {
System.debug('list call failed: ' + meta);
return;
}
Object totalObj = body.get('totalNumberOfRecords');
total = (totalObj == null) ? 0 : (Integer) totalObj;
List<Object> rows = (List<Object>) body.get('data');
if (rows != null) {
for (Object row : rows) {
Map<String, Object> inv = (Map<String, Object>) row;
// TODO: UPSERT into your custom object with returnInventoryId__c
// as External Id. Adjacent windows share a seam day, so the
// same row may be returned twice; UPSERT absorbs the duplicate.
// inv.get('returnInventoryId')
// inv.get('handlingCode')
// inv.get('handlingStatusCode')
// inv.get('warehouseId')
}
}
offset += PAGE_SIZE;
}
windowEnd = windowStart;
}
}
private static String formatGmt(Datetime dt) {
return dt.formatGmt('yyyy-MM-dd\'T\'HH:mm:ss\'Z\'');
}
}
関連
- 返品在庫の詳細を取得 — webhook がキャッシュされていない
returnInventoryIdを参照した場合に、ID で 1 件取得。 - ラインアイテム ID で返品在庫を取得 —
returnRequestLineItemIdで検索。 - 返品在庫ハンドリングを更新 — 書き込み側エンドポイント。
- すべてのハンドリングステータスを取得 と すべてのハンドリングタイプを取得 — コード → ラベルのマッピング。
- Webhooks — 在庫ライフサイクル イベントの正規チャネル。本エンドポイントを利用する前に必ず webhook を設定してください。
承認
Your API key
Your API token — keep this private
クエリパラメータ
Number of records per page (1–50)
必須範囲:
1 <= x <= 50