> For the complete documentation index, see [llms.txt](https://lmile.gitbook.io/lmile-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lmile.gitbook.io/lmile-docs/transfer-api/batches.md).

# Transfer Batches — 倉庫間移動バルク

[出荷元変更](/lmile-docs/oversell-api/source-change.md)（`/api/routing/change-source`）で旧倉庫に残った現品を、**複数まとめて（バルク）宛先倉庫へ送る**ための「箱」の管理です。送り側（旧出荷元）はバルクを作成し、移動対象の単位をユニットQR スキャンで詰めていきます。単位ごとの状態は既存の出荷元変更の状態機械（`change_requested` → `return_in_transit` → `return_received`）をそのまま使い、バルクは `batch_id`（`lm_fulfillment_source_changes.batch_id`）で単位を束ねます。

> **Base URL** `https://api.lmile.io` · **認証** operator JWT（`Authorization: Bearer`）（[詳細](https://lmile.gitbook.io/lmile-docs/transfer-api/pages/7cB70I8yeRnMpvcdLkNu#operator-jwt-認証)） · `shop` は POST はボディ / GET は query に含めます

バルクのライフサイクルは `open`（梱包中・単位の追加/取消可）→ `dispatched`（[発送確定](/lmile-docs/transfer-api/dispatch.md)・内容物確定）→ `received`（[宛先で全単位の受領完了](/lmile-docs/transfer-api/receive.md)、または返送追跡の配送完了検知による自動遷移）です。`dispatched` のバルクは返送ラベルの配送状況をサーバーが定期ポーリング（約 1 時間ごと）し、キャリアが配送完了（delivered）を返すと**ステータスのみ** `received` に自動遷移します（`received_at` と所属単位の受領時刻を記録。中止済みの単位には付与しません。[受領照合](/lmile-docs/transfer-api/receive.md)が行う単位の再フルフィルメント等の副作用は伴いません）。バルクの内容物（単位明細）の一覧は [`GET /api/operator/source-changes`](/lmile-docs/operator-api/queues.md) の `batchId` フィルタで取得します。

## エンドポイント

| Method | Path                                         | 用途                                   | テーブル                                                                                                        |
| ------ | -------------------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `POST` | `/api/operator/transfer/batches`             | バルク作成（`open`）                        | `lm_transfer_batches` / `locations`                                                                         |
| `GET`  | `/api/operator/transfer/batches`             | バルク一覧（status / 送り側 / 受け側で絞り込み + 単位数） | `lm_transfer_batches` / `lm_fulfillment_source_changes` / `locations`                                       |
| `POST` | `/api/operator/transfer/batches/add-unit`    | ユニットQR スキャンで移動対象の単位を追加               | `lm_fulfillment_source_changes` / `lm_fulfillment_units` / `lm_fulfillment_shipments` / `lm_routing_orders` |
| `POST` | `/api/operator/transfer/batches/remove-unit` | 誤スキャンの取消（`open` 中のみ）                 | `lm_fulfillment_source_changes`                                                                             |

***

## `POST` /api/operator/transfer/batches

バルクを作成します。`fromLocationId`（送り側 = 旧出荷元）と `toLocationId`（宛先 = 新出荷元）は出荷元（fulfillment source）の location uuid で、追加できる単位はこの経路（from → to）の出荷元変更ケースに限定されます。

### リクエスト

```http
POST https://api.lmile.io/api/operator/transfer/batches
Authorization: Bearer {OPERATOR_JWT}
Content-Type: application/json
```

```json
{
  "shop": "demo-store.myshopify.com",
  "fromLocationId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
  "toLocationId": "c3d4e5f6-a7b8-9012-cdef-345678901234"
}
```

### ボディパラメータ

| パラメータ            | 型             |  必須 | 説明                                                    |
| ---------------- | ------------- | :-: | ----------------------------------------------------- |
| `shop`           | string        |  ✓  | 店舗ドメイン（スタッフの束縛 shop 内）                                |
| `fromLocationId` | string (uuid) |  ✓  | 送り側 = 旧出荷元の location id                               |
| `toLocationId`   | string (uuid) |  ✓  | 宛先 = 新出荷元の location id（`from` と同一は `422 same_source`） |

### レスポンス

```json
{
  "ok": true,
  "batch": {
    "id": "0d9c5a8e-1234-4abc-9def-0123456789ab",
    "status": "open",
    "fromLocationId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "fromLocationLabel": "大阪MFC",
    "toLocationId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
    "toLocationLabel": "流山倉庫",
    "hasPdf": false,
    "dispatchedAt": null,
    "receivedAt": null,
    "unitCount": 0,
    "inTransitUnitCount": 0,
    "receivedUnitCount": 0,
    "cancelledUnitCount": 0,
    "createdAt": "2026-06-12T09:00:00.000Z",
    "updatedAt": "2026-06-12T09:00:00.000Z"
  }
}
```

### 挙動・冪等性

* 作成のたびに新しいバルクができます（同一経路で複数の `open` バルク = 複数箱は許容）。
* 作成者は `created_by_staff_user_id` に記録されます（operator JWT のスタッフ）。

***

## `GET` /api/operator/transfer/batches

バルクの横断一覧です。送り側は `status=open` で梱包中の箱を、受け側は `status=dispatched` + `toLocationId` で「届くはずの箱」を取得します。一覧は作成日時の降順です。

### リクエスト

```http
GET https://api.lmile.io/api/operator/transfer/batches?shop=demo-store.myshopify.com&status=open,dispatched&fromLocationId=b2c3d4e5-f6a7-8901-bcde-f23456789012&limit=50
Authorization: Bearer {OPERATOR_JWT}
```

| クエリ              | 型      |  必須 | 説明                                                             |
| ---------------- | ------ | :-: | -------------------------------------------------------------- |
| `shop`           | string |  ✓  | 店舗ドメイン（スタッフの束縛 shop 内）                                         |
| `status`         | string |     | 指定時のみステータスでフィルタ（CSV で複数指定可・`open` / `dispatched` / `received`） |
| `fromLocationId` | string |     | 指定時のみ送り側の uuid で絞る                                             |
| `toLocationId`   | string |     | 指定時のみ宛先の uuid で絞る（`fromLocationId` と併用可）                       |
| `limit`          | number |     | 一覧の件数。正整数・既定 `50`・最大 `200`（超過分は `200` に丸め）                     |

### レスポンス

作成時と同じ `batch` 形の配列です。`unitCount`（所属単位数）/ `inTransitUnitCount`（返送中）/ `receivedUnitCount`（受領済）/ `cancelledUnitCount`（中止）を enrich します。

```json
{ "ok": true, "count": 2, "batches": [ { "id": "…", "status": "dispatched", "unitCount": 12, "receivedUnitCount": 4, "…": "…" } ] }
```

***

## `POST` /api/operator/transfer/batches/add-unit

ユニットQR（`<barcode>|<shipmentId>`、[統合QR 規格](/lmile-docs/shelf-api/lookup.md)）のスキャンで移動対象の単位をバルクに追加します。**移動対象かどうかの判定はサーバー側**で行い、出荷元変更ケースが `change_requested` かつ単位が `source_change_pending` のものだけを受け付けます（それ以外は `error_kind` で明示拒否。黙って通しません）。

### リクエスト

```http
POST https://api.lmile.io/api/operator/transfer/batches/add-unit
Authorization: Bearer {OPERATOR_JWT}
Content-Type: application/json
```

```json
{
  "shop": "demo-store.myshopify.com",
  "batchId": "0d9c5a8e-1234-4abc-9def-0123456789ab",
  "qr": "4912345678901|aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
}
```

### ボディパラメータ

| パラメータ     | 型             |  必須 | 説明                     |
| --------- | ------------- | :-: | ---------------------- |
| `shop`    | string        |  ✓  | 店舗ドメイン（スタッフの束縛 shop 内） |
| `batchId` | string (uuid) |  ✓  | 追加先バルク（`open` のみ）      |
| `qr`      | string        |  ✓  | ユニットQR の生値（\`          |

### レスポンス

```json
{
  "ok": true,
  "batchId": "0d9c5a8e-1234-4abc-9def-0123456789ab",
  "added": true,
  "sourceChangeId": "cccccccc-dddd-eeee-ffff-000000000000",
  "unit": { "id": "…", "barcode": "4912345678901", "lineInstanceNo": 1, "status": "source_change_pending" },
  "order": { "id": "…", "orderNumber": "1001", "sourceSystem": "shopify" },
  "unitCount": 5
}
```

### 挙動・冪等性

* 移動中の単位は出荷元変更の起票時に**新拠点のヘッダへ relink 済み**のため、印字 QR の `shipmentId`（旧ヘッダ）→ 注文 → 同 barcode の単位、の経路で解決します。
* ケースの経路（from / to）がバルクの経路と一致するものだけ追加できます（不一致は `422 batch_route_mismatch`）。
* 同一バルクへの再スキャンは `200` の no-op（`added: false, alreadyInBatch: true`）。別バルク所属は `409 already_in_batch`。
* 同 barcode の複数単位は未所属の先頭（`lineInstanceNo` 昇順）から 1 件ずつ追加されます。

***

## `POST` /api/operator/transfer/batches/remove-unit

誤スキャンの取消です。バルクが `open` の間だけ、所属（`batch_id`）を外します。

### リクエスト

```json
{
  "shop": "demo-store.myshopify.com",
  "batchId": "0d9c5a8e-1234-4abc-9def-0123456789ab",
  "sourceChangeId": "cccccccc-dddd-eeee-ffff-000000000000"
}
```

| パラメータ            | 型             |  必須 | 説明                                    |
| ---------------- | ------------- | :-: | ------------------------------------- |
| `shop`           | string        |  ✓  | 店舗ドメイン                                |
| `batchId`        | string (uuid) |  ✓  | 対象バルク（`open` のみ）                      |
| `sourceChangeId` | string (uuid) |  ✓  | 外す出荷元変更ケース（add-unit / 内容物一覧のレスポンスで取得） |

### レスポンス

```json
{ "ok": true, "batchId": "…", "removed": true, "sourceChangeId": "…", "unitCount": 4 }
```

既に外れている場合は `200` の no-op（`removed: false, alreadyRemoved: true`）。別バルク所属は `409 not_in_batch`。

## エラー

エンドポイント固有:

| Status | 条件                                                                           | レスポンス例                                                                                         |
| :----: | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|  `422` | `from` と `to` が同一 / 拠点が shop に存在しない（作成）                                      | `{ "ok": false, "error_kind": "same_source" }` / `{ "error_kind": "location_not_found" }`      |
|  `400` | `status` が許可値外（一覧）                                                           | `{ "ok": false, "error_kind": "invalid_status", "allowed": ["open","dispatched","received"] }` |
|  `404` | バルク / ケース / shipment / unit が存在しない                                           | `{ "ok": false, "error_kind": "batch_not_found" }` 等                                           |
|  `409` | バルクが `open` でない（追加 / 取消）                                                     | `{ "ok": false, "error_kind": "batch_not_open" }`                                              |
|  `422` | ユニットQR 形式不正 / 旧規格                                                            | `{ "ok": false, "error_kind": "invalid_qr" }` / `{ "error_kind": "legacy_qr" }`                |
|  `422` | 移動対象でない（`source_change_pending` × `change_requested` 以外。`unitStatuses[]` 同梱） | `{ "ok": false, "error_kind": "not_transfer_target", "unitStatuses": [...] }`                  |
|  `422` | ケースの経路がバルクと不一致                                                               | `{ "ok": false, "error_kind": "batch_route_mismatch", "batchRoute": {...} }`                   |
|  `409` | 同 barcode の対象が全て別バルク所属                                                       | `{ "ok": false, "error_kind": "already_in_batch", "otherBatchIds": [...] }`                    |

共通エラー（`401` / `400` 共通形 / `403` / `405` / `500` / `503`）は [Error Codes](/lmile-docs/reference/error-codes.md) を参照。

## データモデル

* `sot.lm_transfer_batches` — バルク本体（経路 = `from/to_location_id` / status / PDF パス / 作成者 `created_by_staff_user_id`）。発送・受領の操作者監査は単位側 `lm_fulfillment_source_changes.updated_by_staff_user_id`。
* merchant Web UI（lmile.io）の read は `agent_read.lm_transfer_batches` / `lm_transfer_batch_units`（safe view）。
* `sot.lm_fulfillment_source_changes.batch_id` — 単位とバルクの関連（nullable FK・1 ケース最大 1 バルク所属）。
* read 用の集計は本 API と [`GET /api/operator/source-changes`](/lmile-docs/operator-api/queues.md)（`batchId` フィルタ）。


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://lmile.gitbook.io/lmile-docs/transfer-api/batches.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
