> 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/routing-api/orders.md).

# Orders — 受注ルーティング

任意のカートシステム（Shopify / BASE / 自社 EC 等）から受注と **出荷元(fulfillment source)ロケーションID** を送ると、その出荷元に紐づく **在庫ロケーション(member)内だけ** で引き当て先を判定し、拠点ごとに分割した **canonical 出荷指示** を生成します。外部 fulfillment（WMS / 3PL）への push と同期レスポンスでの返却を同時に行います。Shopify orders webhook に依存しない cart-agnostic な汎用エンドポイントです。

> **出荷元 (fulfillment source)** = 実際に出荷する拠点（例: MFCセンター東京）。**在庫ロケーション (inventory location)** = 在庫を持つ倉庫・店舗。1つの出荷元に複数の在庫ロケーションが紐づき（1出荷元 : N在庫）、出荷元の販売可能在庫はメンバー在庫の合算です。紐付けは `sot.lm_fulfillment_source_members` で管理します。

> **Base URL** `https://api.lmile.io` · **認証** `x-ingest-secret` ヘッダー（[詳細](/lmile-docs/getting-started/authentication.md)） · `shop` はリクエストボディに含めます（省略するとキーのアカウント）

## エンドポイント

| Method | Path                                 | 用途                                       |
| ------ | ------------------------------------ | ---------------------------------------- |
| `POST` | `/api/routing/orders`                | 受注を受け取り出荷元を判定 → 出荷指示を生成・dispatch         |
| `POST` | `/api/routing/orders/shipped`        | 取込元で引き渡しが終わっている注文（店頭販売など）を、その拠点から出荷済みで登録 |
| `POST` | `/api/routing/orders/shipped/cancel` | 上記で登録した注文を、取込元の取消（取消取引・全額返品）に合わせて取消にする   |

> 入力フィールドは **camelCase**（`sourceSystem` / `externalOrderRef` / `fulfillmentSourceLocationId` / `shipTo` / `idempotencyKey`）です。ingest 系の snake\_case とは異なる点に注意してください。

***

## `POST` /api/routing/orders

受注 1 件を受け取り、明細を unit（数量 1 個）単位で拠点へ配分し、出荷元ごとにまとめた出荷指示を返します。

### リクエスト

```http
POST https://api.lmile.io/api/routing/orders
x-ingest-secret: {INGEST_SECRET}
Content-Type: application/json
```

```json
{
  "shop": "demo-store.myshopify.com",
  "sourceSystem": "shopify",
  "externalOrderRef": "1001",
  "fulfillmentSourceLocationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "channel": "online_store",
  "idempotencyKey": "shopify:1001",
  "tag": "express",
  "shipTo": {
    "name": "山田 太郎",
    "company": null,
    "phone": "+819012345678",
    "email": "taro@example.com",
    "country": "JP",
    "postalCode": "150-0001",
    "prefecture": "東京都",
    "city": "渋谷区",
    "address1": "道玄坂1-2-3",
    "address2": "○○ビル 4F"
  },
  "lines": [
    { "barcode": "1234567890123", "quantity": 2 },
    { "barcode": "1234567890456", "quantity": 1, "properties": { "刻印": "T.Y", "ギフト包装": "あり" } }
  ]
}
```

### ボディパラメータ

| パラメータ                         | 型              |  必須 | 説明                                                                                                                                                                                                                                                                                                   |
| ----------------------------- | -------------- | :-: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `shop`                        | string         |     | 店舗ドメイン（省略するとキーのアカウント）                                                                                                                                                                                                                                                                                |
| `sourceSystem`                | string         |  ✓  | カートの種別（`shopify` / `base` / `self_ec` 等、任意の識別子）。注文 identity・冪等キーの一部                                                                                                                                                                                                                                  |
| `externalOrderRef`            | string         |  ✓  | カート側の注文番号。注文 identity の一部                                                                                                                                                                                                                                                                            |
| `orderName`                   | string         |     | カート側の表示用注文番号（例 `BJP999711`）。倉庫間移動の内容物リスト（出荷ID配載 = W+数値部）・入荷予定 `order_no` の元値                                                                                                                                                                                                                         |
| `referenceUrl`                | string (url)   |     | カート側の注文参照 URL（例 Shopify admin の注文ページ `https://admin.shopify.com/store/{handle}/orders/{id}`）。管理 UI が注文番号からカート管理画面へ遷移するリンクに使う。`http(s)` のみ                                                                                                                                                            |
| `fulfillmentSourceLocationId` | string (uuid)  |  ✓  | 出荷元 location の id。**この出荷元に紐づく在庫ロケーション内だけ**で引き当てる                                                                                                                                                                                                                                                     |
| `inventoryLocationId`         | string (uuid)  |     | 引き当て先 在庫ロケーションの明示指定（任意）。指定時は**この location のみ**に引き当て（他メンバーへは振らない）。出荷元にマッピングされていなければ `422`                                                                                                                                                                                                             |
| `deliveryMethod`              | string         |     | `shipping`（既定）/ `pickup`（店舗受け取り）。`pickup` のときは **`fulfillmentSourceLocationId` が受け取り店舗**で、引き当てもその店舗に固定します（出荷元に在庫ロケーションが複数あるときは `inventoryLocationId` が必須。無ければ `422 pickup_requires_inventory_location`）。配送ラベルは発行しません。受取待ち / 引渡し済みは [Store Pickup](/lmile-docs/fulfillment-api/store-pickup.md) で進めます |
| `suppressCustomerMail`        | boolean        |     | `true` にすると、この注文では購入者にお届け状況メールを送りません（全段階とキャンセルのお知らせ）。一度指定すると取り消せません。省略時は店舗の通知設定どおり                                                                                                                                                                                                                   |
| `suppressStorePrint`          | boolean        |     | `true` にすると、この振り分けでは引き当て先の店舗で商品ラベル（統合QR）を自動印刷しません。引き当ての通知（[Routing Allocation Webhook](/lmile-docs/webhooks/allocation.md)）は通常どおり送ります。省略時は印刷します                                                                                                                                                      |
| `lines`                       | array          |  ✓  | 受注明細（1〜1,000 件）                                                                                                                                                                                                                                                                                      |
| `channel`                     | string         |     | 販売チャネル（`channel_code` または `channel_id` の UUID）。未解決でも在庫・拠点優先度で続行                                                                                                                                                                                                                                      |
| `shipTo`                      | object         |     | 配送先（`prefecture` を region 判定に使用）                                                                                                                                                                                                                                                                     |
| `idempotencyKey`              | string         |     | 冪等キー。省略時は `{sourceSystem}:{externalOrderRef}` を自動採用                                                                                                                                                                                                                                                  |
| `tag`                         | string         |     | ディスパッチ先(WMS)選択の条件 tag（任意・単一）。[Dispatch Config](/lmile-docs/configuration/dispatch-config.md) の tag 一致設定を優先、無ければ既定。引き当て(routing)自体には影響しない                                                                                                                                                             |
| `desiredDeliveryDate`         | string \| null |     | 配達希望日（ISO `YYYY-MM-DD`）。カート側が Shopify メタフィールド `custom.pickup_date` から取得。[ラベル生成時](/lmile-docs/fulfillment-api/fulfillment.md)に Ship\&Co `setup.date`（配達指定日）へ載って佐川送り状へ印字。指定なしは未指定／`null`。後から手で設定する場合は [Shipment Delivery](/lmile-docs/fulfillment-api/shipment-delivery.md)                            |
| `desiredDeliveryTime`         | string \| null |     | 配達希望時間帯（元表記。例 `"午前中"` / `"12:00-14:00"`）。`custom.pickup_time` 由来。ラベル生成時に佐川コード（`before-noon` / `12-14` 等）へ変換し `setup.time` へ載せる。佐川が認識しない表記は時間指定なし扱い                                                                                                                                                   |

#### `shipTo` オブジェクト

Shopify `MailingAddress` / ship\&co 準拠。全フィールド任意。出荷指示・WMS ディスパッチのテンプレート変数として使えます。

| パラメータ        | 型      |  必須 | 説明                                           |
| ------------ | ------ | :-: | -------------------------------------------- |
| `name`       | string |     | 受取人氏名（ship\&co `full_name` / Shopify `name`） |
| `company`    | string |     | 会社名                                          |
| `phone`      | string |     | 電話番号（E.164 推奨）                               |
| `email`      | string |     | メールアドレス                                      |
| `country`    | string |     | 国コード（ISO-3166-1 alpha-2、例 `JP`）              |
| `postalCode` | string |     | 郵便番号（`zip`）                                  |
| `prefecture` | string |     | 都道府県（→ region に解決し地域一致スコアに使用。**日本語都道府県名**）   |
| `city`       | string |     | 市区町村                                         |
| `address1`   | string |     | 番地・町名                                        |
| `address2`   | string |     | 建物名・部屋番号                                     |

#### `lines[]` オブジェクト

| パラメータ        | 型      |  必須 | 説明                                                                                                                                                                                                                    |
| ------------ | ------ | :-: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `barcode`    | string |  ✓  | 商品識別子（`sot.products` との結合キー）                                                                                                                                                                                          |
| `quantity`   | number |  ✓  | 数量（整数 1〜10,000）。unit 単位で拠点へ配分                                                                                                                                                                                         |
| `properties` | object |     | 明細単位の任意キー/値（刻印テキスト・名入れ・ギフト指定等。Shopify line item property 相当）。最大 20 キー、キーは 1〜100 文字・値は 500 文字以内の文字列。省略 / `null` / 空 object は「なし」扱い。**同一 `barcode` でも `properties` が異なる明細は別行のまま**出荷指示・ピッキングリスト・dispatch payload へ透過されます |

### レスポンス

```json
{
  "ok": true,
  "routingOrderId": "0f1e2d3c-4b5a-6789-0abc-def123456789",
  "status": "dispatched",
  "shippingInstruction": {
    "shop": "demo-store.myshopify.com",
    "routingOrderId": "0f1e2d3c-4b5a-6789-0abc-def123456789",
    "sourceSystem": "shopify",
    "externalOrderRef": "1001",
    "idempotencyKey": "shopify:1001",
    "shipTo": { "country": "JP", "prefecture": "東京都", "city": "渋谷区", "postalCode": "150-0001" },
    "shipments": [
      {
        "fromLocationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "fromLocationLabel": "東京DC",
        "lines": [
          { "barcode": "1234567890123", "quantity": 2, "properties": null },
          { "barcode": "1234567890456", "quantity": 1, "properties": { "刻印": "T.Y", "ギフト包装": "あり" } }
        ]
      }
    ],
    "unroutableLines": [],
    "serviceLines": [],
    "decidedAt": "2026-06-02T03:34:56.000Z"
  },
  "dispatches": [
    { "locationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "sent", "httpStatus": 200, "attempts": 1 }
  ]
}
```

| フィールド                                             | 説明                                                                                                                                                                                        |
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ok`                                              | 通常 `true`。外部 dispatch が `failed` のときのみ `false`（HTTP は 200）                                                                                                                                |
| `routingOrderId`                                  | routing order ヘッダの id（`sot.lm_routing_orders.id`）                                                                                                                                         |
| `status`                                          | `received` / `routed` / `dispatched` / `failed` / `no_stock`                                                                                                                              |
| `shippingInstruction`                             | 拠点別に分割した canonical 出荷指示（下記）                                                                                                                                                               |
| `dispatches`                                      | 引き当て先ロケーションごとの送信結果配列（各 `locationId` / `status`: `sent`/`failed`/`skipped` / `httpStatus` / `attempts` / `error`）。送信先は [Dispatch Config](/lmile-docs/configuration/dispatch-config.md) で登録 |
| `idempotent`                                      | 既に `dispatched` 済の注文を再 POST した場合のみ `true`（再ルーティングせず既存結果を返却）                                                                                                                               |
| `customerMailSuppressed` / `storePrintSuppressed` | `suppressCustomerMail` / `suppressStorePrint` を受け付けたか。送った指定が `false` で返ってきたら、止まっていません                                                                                                     |

#### `shippingInstruction`

| フィールド               | 説明                                                                                                                                                     |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `shipments[]`       | 出荷元拠点ごとの出荷単位。`fromLocationId` / `fromLocationLabel` と `lines[]`（`barcode` / `quantity` / `properties`。同一 `barcode` でも `properties` が異なれば別行。なしは `null`） |
| `unroutableLines[]` | 引き当て不能だった分。`barcode` / `quantity` / `reason`（`no_stock_anywhere` 等）/ `properties`                                                                      |
| `serviceLines[]`    | 非在庫サービス品（刻印サービス等、`sot.products.is_non_inventory = true`）の明細。`barcode` / `quantity` / `properties`。在庫引き当ての対象外（`unroutableLines` には含まれない）                |
| `decidedAt`         | 判定時刻（ISO 8601, UTC）                                                                                                                                    |

### ルーティング判定ロジック

各明細を unit 単位に展開し、**指定された出荷元のメンバー在庫ロケーション**を候補に順位付けして、在庫の続く限り上位拠点から greedy に配分します。

* **候補拠点**: 指定された出荷元に紐づく **有効な在庫ロケーション（member）のみ**（`sot.lm_fulfillment_source_members` の `is_active = true`）。出荷元の外の拠点や `ec_fulfillable` フラグは判定に使いません（出荷元が EC 出荷の主体、member は在庫源）。
* **在庫除外**: 当該 barcode の `routable = available_qty + committed_qty` が 0 以下、または在庫レコード無しの member は除外（`out_of_stock`）。在庫の無い拠点には引き当てません。`committed_qty` の送り方は [Inventory Levels](/lmile-docs/ingestion-api/inventory-levels.md) を参照。
* **非在庫サービス品の除外**: `sot.products.is_non_inventory = true` の商品（刻印サービス等、物理在庫を持たないサービス/カスタム明細）は**在庫引き当ての対象外**です。該当 unit は `unroutableLines` ではなく `serviceLines` に分類され、判定根拠には `reason: non_inventory_service` が記録されます（フラグの設定は ops の明示操作のみ。SKU や品名による自動判定はしません）。
* **SKU 拠点オーバーライド**（`sot.lm_sku_location_overrides`）:
  * `force_only` — その拠点のみを候補にする
  * `avoid` — その拠点を除外する
  * `force_first` — その拠点を常に最優先で引き当てる
* **引き当て順**: 在庫のある候補を次の順で並べます — ① `force_first` 指定拠点 ② **出荷元自身の在庫**（自己在庫を使い切ってから店舗メンバーへ）③ **販売可能在庫（`available_qty`）の多い順** ④ 配送先 region と拠点 region の一致 ⑤ member の `priorityRank` 昇順（未設定は最後）。`committed_qty` は順位には使わず、引き当て可否（`routable > 0`）と配分数の上限にのみ使います。スコア内訳（拠点優先度・地域一致・在庫量スコア等）は判定根拠として保存されますが、順位の決定には使いません。
* **配分**: 順位の上位から数量を unit 単位で greedy 配分。在庫が尽きて余った unit は `unroutableLines`（`no_stock_anywhere`）になります。
* **明細のグルーピング**: 同一 `barcode` の複数明細（`properties` 違い等）は**合算して 1 回で引き当て**ます（別々に引き当てると在庫を二重参照するため）。引き当て後、unit（`lineInstanceNo` = 注文内 barcode 単位の連番）へ元明細の順に `properties` を配り戻し、出荷指示・ピッキングリストでは **`barcode` × `properties` 単位**で行を分けて集計します。
* **引き当て先の明示指定**: `inventoryLocationId` を指定すると候補を**その location のみ**に限定します（出荷元の他メンバーへは振らない）。指定 location が出荷元にマッピングされていなければ `422 location_not_member_of_source`。在庫不足分は `unroutableLines`。

> 出荷後に在庫が実際には無かった（売越し）場合は、`/api/routing/oversell` で該当結果に売越しフラグを立て、`/api/routing/reallocate` で**同一出荷元の別メンバー**へ再引き当てできます（[Oversell / Reallocate](/lmile-docs/oversell-api/oversell-reallocate.md)）。

判定の根拠（拠点別スコア内訳・除外理由・採用理由）は `sot.lm_routing_decisions` / `sot.lm_routing_candidates` に監査ログとして保存されます。

### 挙動・冪等性

* **入口冪等**: `(shop, sourceSystem, externalOrderRef)` で routing order 1 行に収束します。`status = dispatched` の注文を再 POST すると、**再ルーティングせず**既存の出荷指示を `idempotent: true` で返します。
* **再ルーティング**: まだ dispatch されていない既存注文の再 POST は、前回の decision を破棄して再計算します。
* **出口冪等**: 出荷指示は `(shop, idempotencyKey)` で upsert され、外部への二重送信を防ぎます。
* **外部 dispatch（per-location）**: 引き当て先の在庫ロケーションごとに登録された WMS 設定（[Dispatch Config](/lmile-docs/configuration/dispatch-config.md)）でテンプレート描画して送信します（5xx は指数バックオフで最大 2 回再試行）。設定の無いロケーションは skip。結果は `dispatches[]` で返し、`sot.lm_location_dispatch_log` に記録します（ルーティング結果は常に保存・返却）。
* **在庫無し**: 引き当てられた unit が 1 つも無ければ `status = no_stock`、dispatch は skip（非在庫サービス品のみの注文も引き当て対象 unit が無いため `no_stock` になります）。
* **dispatch 失敗時**: HTTP は `200` のまま `ok: false` / `status: failed` を返します（ルーティングは成功・保存済、外部送信のみ失敗）。
* ルーティング完了直後の引き当て結果は [Routing Allocation Webhook](/lmile-docs/webhooks/allocation.md) で外部へ通知されます（設定時のみ。引き当て不能明細・`no_stock` も `unallocated` イベントとして通知）。
* **出荷元の確認待ち**: 出荷元を引き当ての前に確認するアプリを登録したストアでは、送った `fulfillmentSourceLocationId` と別の出荷元で引き当てることがあります。確認が取れないときは引き当てずに HTTP `202` で `status = received` / `pending: "source_decision"` / `routingOrderId: null` を返し、確認が取れた時点でサーバー側が自動で引き当てます。**再送は不要です**（再送しても二重には引き当たりません）。アプリを登録していないストアでは起きません。
* **通知・印刷を止める**: 誤出荷の再手配など、購入者に知らせずに引き当てたいときは `suppressCustomerMail: true` を付けます。店舗での商品ラベルの印刷も要らないときは、あわせて `suppressStorePrint: true` を付けます。印刷を止めた注文を後から印刷したいときは、コンソールの出荷詳細から再印刷できます。

***

## `POST` /api/routing/orders/shipped

取込元で既に引き渡しが終わっている注文（店頭販売など）を、受注と **その拠点から出荷済みの出荷** として登録します。引き当て・在庫・配送ラベル・購入者への通知は動きません。

### リクエスト

```http
POST https://api.lmile.io/api/routing/orders/shipped
x-ingest-secret: {INGEST_SECRET}
Content-Type: application/json
```

```json
{
  "shop": "demo-store.myshopify.com",
  "sourceSystem": "smaregi",
  "externalOrderRef": "12345",
  "orderName": "BJP1000001",
  "referenceUrl": "https://www1.smaregi.jp/control/transaction/detail.html?transactionHeadId=12345",
  "location": { "identifier_type": "smaregi_store_id", "identifier_value": "35" },
  "shippedAt": "2026-10-09T11:22:33+09:00",
  "channel": "store",
  "lines": [
    { "barcode": "1234567890123", "quantity": 2, "title": "レザーバッグ" }
  ]
}
```

### ボディパラメータ

| パラメータ              | 型       |  必須 | 説明                                                                                                                                                                                                                                                       |
| ------------------ | ------- | :-: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `shop`             | string  |  ✓  | 店舗ドメイン                                                                                                                                                                                                                                                   |
| `sourceSystem`     | string  |  ✓  | 取込元の識別子（例 `smaregi`）                                                                                                                                                                                                                                     |
| `externalOrderRef` | string  |  ✓  | 取込元の注文 ID（例 スマレジの取引 ID）。`sourceSystem` との組で 1 注文                                                                                                                                                                                                         |
| `orderName`        | string  |     | 人が読む注文番号（例 `BJP1000001`）                                                                                                                                                                                                                                 |
| `referenceUrl`     | string  |     | 取込元の注文ページ URL（http(s) のみ）                                                                                                                                                                                                                                |
| `locationId`       | uuid    |  △  | 出荷した拠点（= 引き当て拠点 = 出荷元）。`location` とどちらか一方                                                                                                                                                                                                                |
| `location`         | object  |  △  | 取込元の識別子で拠点を指す `{ "identifier_type", "identifier_value" }`（例 `smaregi_store_id`）。`locationId` とどちらか一方                                                                                                                                                     |
| `shippedAt`        | string  |  ✓  | 引き渡した日時（ISO 8601。オフセット付き可）                                                                                                                                                                                                                               |
| `orderedAt`        | string  |     | 注文の日時（ISO 8601）。受注の作成日時になります。省略すると `shippedAt`                                                                                                                                                                                                           |
| `channel`          | string  |     | 販売チャネル（`channel_code` か UUID。例 `store`）                                                                                                                                                                                                                  |
| `shipTo`           | object  |     | 宛先（任意。項目は `/api/routing/orders` と同じ）                                                                                                                                                                                                                     |
| `lines[]`          | array   |  ✓  | 明細（1〜1000 行）。`barcode` / `quantity`（1 以上）と、任意の `title` / `variantTitle`                                                                                                                                                                                  |
| `idempotencyKey`   | string  |     | 省略時 `{sourceSystem}:{externalOrderRef}`                                                                                                                                                                                                                  |
| `dryRun`           | boolean |     | `true` で下見: 拠点の解決と判定だけ行い、何も書きません。`{ "ok": true, "dryRun": true, "decision": "create" \| "exists" \| "cancelled" \| "leg_cancelled" \| "order_has_units", "units": 作る単位の数, "skippedLines": [...] }` を返します（`exists` のときは既にある出荷の `shipmentId` / `status` も） |

### レスポンス

```json
{
  "ok": true,
  "routingOrderId": "0b2a1c3d-...",
  "shipmentId": "3f2a1b0c-...",
  "status": "shipped",
  "idempotent": false,
  "skippedLines": [{ "barcode": "4900000000099", "quantity": 1, "reason": "non_inventory_service" }]
}
```

| フィールド            | 説明                                                                          |
| ---------------- | --------------------------------------------------------------------------- |
| `routingOrderId` | 受注の ID                                                                      |
| `shipmentId`     | 作られた（または既にあった）出荷の ID                                                        |
| `idempotent`     | `true` = その拠点の出荷が既にあり、何も変更していない（このときは `skippedLines` を返しません）                |
| `skippedLines[]` | 単位を作らなかった明細。`non_inventory_service` = 現物の無い同梱品（商品マスターで非在庫かつ付帯サービス。刻印サービスなど） |

### 挙動・冪等性

* 送ると、受注 1 件とその拠点からの出荷 1 件（明細は数量ぶんの単位）が **出荷済み** で作られます。お届け状況は「発送済み」になります。受注の作成日時は `orderedAt`（省略時 `shippedAt`）、出荷の作成日時は `shippedAt` です（過去の注文を後から登録しても、一覧の「直近」には並びません）。
* `channel` が店舗のチャネル（チャネルの種別が `store`。スマレジの取引など）なら、購入者がその場で受け取っているので、お届け状況は **配達完了**（配達完了日時 = `shippedAt`）になります。それ以外のチャネルや `channel` 省略時は「発送済み」のままです。
* 現物の無い同梱品（商品マスターで非在庫かつ付帯サービス。刻印サービスなど）の明細は単位を作らず `skippedLines[]` で返します。紙袋のように現物のある非在庫品は単位になります（引き当てと同じ扱い）。
* 引き当て・在庫の予約・棚・配送ラベル・出荷指示の送信・引き当て通知・出荷ステータスの通知（[Fulfillment Status Webhook](/lmile-docs/webhooks/fulfillment-status.md)）・購入者へのメールはどれも動きません。拠点の販売可能在庫は変わりません（店頭の在庫は取込元が正）。
* 出荷元の設定（出荷元とそのメンバー）は見ません。指定した拠点がそのまま出荷元になります。
* **冪等**: 同じ注文にその拠点から出る出荷が既にあれば、作らずに `idempotent: true` と実際の `status` を返します。そのまま再送してよいです。「同じ注文」は `externalOrderRef` が同じもの、または `{externalOrderRef}-…` の形（拠点・刻印・別の荷物・海外再発送で分けた注文）を含みます。この受け口が作った出荷なら、途中で失敗して欠けた単位を埋め直します。他の経路の出荷（引き当て済み・出荷元変更後など）には触りません。
* 同じ注文で別の拠点を送ると、その拠点の出荷が追加されます（複数の店舗から渡した注文）。ただし、その注文に別の拠点の生きた単位があるときは `409 order_has_units` で作りません。
* 同じ注文・同じ拠点に取消済みの出荷があるときは作り直しません（`409 leg_cancelled`）。
* 商品マスターに無い `barcode` も登録します（SKU は空のまま）。
* 取消済みの注文には登録しません（`409 order_cancelled`）。

***

## `POST` /api/routing/orders/shipped/cancel

`/api/routing/orders/shipped` で登録した注文が取込元で取り消されたとき（スマレジの取消取引・全額返品など）、その受注と出荷・単位を **取消** にします。在庫・配送ラベル・購入者や現場への通知は動きません。

### リクエスト

```http
POST https://api.lmile.io/api/routing/orders/shipped/cancel
x-ingest-secret: {INGEST_SECRET}
Content-Type: application/json
```

```json
{
  "shop": "demo-store.myshopify.com",
  "sourceSystem": "smaregi",
  "externalOrderRef": "138600",
  "cancelledAt": "2026-10-12T13:20:00+09:00",
  "reason": "smaregi dispose 138603"
}
```

### ボディパラメータ

| パラメータ              | 型      |  必須 | 説明                                                      |
| ------------------ | ------ | :-: | ------------------------------------------------------- |
| `shop`             | string |  ✓  | 店舗ドメイン                                                  |
| `sourceSystem`     | string |  ✓  | 取込元の識別子（例 `smaregi`）                                    |
| `externalOrderRef` | string |  ✓  | 取込元の注文 ID（登録時と同じ値）                                      |
| `cancelledAt`      | string |     | 取り消した日時（ISO 8601）。省略すると受信時刻                             |
| `reason`           | string |     | 取消の理由（200 文字まで。出荷の取消理由として残ります。省略時 `external_cancelled`） |

### レスポンス

```json
{
  "ok": true,
  "idempotent": false,
  "routingOrderId": "0b2a1c3d-...",
  "cancelledShipments": 1,
  "cancelledUnits": 2
}
```

| フィールド                                   | 説明                            |
| --------------------------------------- | ----------------------------- |
| `idempotent`                            | `true` = 注文が既に取消済みで、何も変更していない |
| `cancelledShipments` / `cancelledUnits` | 取消にした出荷と単位の数                  |

### 挙動・冪等性

* 送ると、受注と、その注文のすべての出荷・単位が **取消** になります。お届け状況は配達完了からでも「取消」になります（`/orders/shipped` で登録した出荷に限ります）。
* 対象は `/orders/shipped` で登録した出荷だけです。引き当てを通った出荷や、倉庫からの出荷実績で出荷済みになった出荷が 1 つでも生きていれば、注文ごと `409 leg_not_external` で断ります（そちらは [`/api/routing/cancel`](/lmile-docs/routing-api/cancel-update.md) を使います。出荷済みの出荷は取り消せません）。
* 在庫・棚・出荷指示の送信・取消の通知（[Routing Cancel Webhook](https://github.com/falcon0119/inventory-os/tree/main/docs/webhooks/routing-cancel.md)）・購入者へのメール・アプリ配信はどれも動きません。
* **冪等**: 注文が既に取消済みなら `idempotent: true` で何も変えません。そのまま再送してよいです。
* 登録されていない注文は `404 not_found` です（取り消すものがありません）。

***

## エラー

エンドポイント固有:

| Status | 条件                                                              | レスポンス例                                                                                                                                                                              |
| :----: | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|  `400` | バリデーション失敗（`fulfillmentSourceLocationId` 欠落・非 UUID 含む）           | `{ "ok": false, "error": "invalid_input", "details": [{ "path": "fulfillmentSourceLocationId", "message": "..." }] }`                                                               |
|  `422` | 出荷元が shop 内に存在しない                                               | `{ "ok": false, "error_kind": "fulfillment_source_unresolved", "error": "fulfillment source location not found for shop" }`                                                         |
|  `422` | 出荷元に有効メンバーが無い                                                   | `{ "ok": false, "error_kind": "fulfillment_source_no_members", "error": "fulfillment source has no active inventory-location members" }`                                            |
|  `422` | 指定 `inventoryLocationId` が出荷元のメンバーでない                           | `{ "ok": false, "error_kind": "location_not_member_of_source", "error": "specified inventory location is not mapped to the fulfillment source" }`                                   |
|  `400` | `/orders/shipped`: `locationId` と `location` の両方、またはどちらも無い      | `{ "ok": false, "error": "invalid_input", "details": [{ "path": "locationId", "message": "..." }] }`                                                                                |
|  `422` | `/orders/shipped`: 拠点が解決できない（`locationId` が shop に無い / 識別子が未登録） | `{ "ok": false, "error_kind": "location_unresolved", "error": "no location for smaregi_store_id=35" }`                                                                              |
|  `422` | `/orders/shipped`: 識別子に複数の拠点が登録されている                            | `{ "ok": false, "error_kind": "location_ambiguous", "error": "multiple locations for smaregi_store_id=35" }`                                                                        |
|  `409` | `/orders/shipped`: 注文が取消済み                                      | `{ "ok": false, "error_kind": "order_cancelled", "error": "routing order is cancelled; not registering shipped leg" }`                                                              |
|  `409` | `/orders/shipped`: 同じ注文・同じ拠点に取消済みの出荷がある                         | `{ "ok": false, "error_kind": "leg_cancelled", "error": "a cancelled leg already exists for this order at this location; not recreating", "shipmentId": "..." }`                    |
|  `409` | `/orders/shipped`: 注文に別の拠点の生きた単位がある                             | `{ "ok": false, "error_kind": "order_has_units", "error": "routing order already has active units at another location; not adding a shipped leg" }`                                 |
|  `404` | `/orders/shipped/cancel`: 注文が登録されていない                           | `{ "ok": false, "error_kind": "not_found", "error": "routing order not found" }`                                                                                                    |
|  `409` | `/orders/shipped/cancel`: `/orders/shipped` で登録したのではない生きた出荷がある  | `{ "ok": false, "error_kind": "leg_not_external", "error": "routing order has a leg that was not registered as externally shipped; use /api/routing/cancel", "shipmentId": "..." }` |

引き当て不能の明細はエラーではなく、レスポンス `shippingInstruction.unroutableLines[]` に `reason` 付きで返ります（正常処理を止めません）。非在庫サービス品（`is_non_inventory = true`）の明細は `unroutableLines` ではなく `serviceLines[]` に分類されます。共通エラー（`401` / `400` / `403` / `405` / `500` / `503`）は [Error Codes](/lmile-docs/reference/error-codes.md) を参照。

## データモデル

* `sot.lm_fulfillment_source_members` — 出荷元 → 在庫ロケーション 紐付け（1出荷元 : N在庫。UNIQUE `shop + inventory_location_id`）
* `sot.lm_routing_orders` — routing-native の注文ヘッダ（入口冪等。UNIQUE `shop + source_system + external_order_ref`）。`status`: `received` / `routed` / `dispatched` / `failed` / `no_stock`
* `sot.lm_routing_decisions` — unit 単位の判定結果（`routing_order_id` / `barcode` / `line_instance_no` / `line_properties`（= `lines[].properties`。名入れ等は顧客 PII になり得るため `agent_read` 非公開）、`fulfillment_source_location_id` = 指定出荷元、`selected_location_id` = 引き当て先在庫ロケーション、`decision_status = applied`。売越し時は `oversold` / `superseded_by_decision_id`）
* `sot.lm_routing_candidates` — 判定時の候補スコア snapshot（拠点別スコア内訳・除外理由・rank）
* `sot.lm_shipping_instructions` — 出荷指示 dispatch ログ（`delivery_status`: `pending` / `sent` / `failed` / `skipped`。UNIQUE `shop + idempotency_key`）
* `sot.lm_fulfillment_shipments` / `sot.lm_fulfillment_units` — `/orders/shipped` が直接作る出荷と単位（`status = shipped`・decision 無し・在庫中立マーカー `shelf_released_at` 付き）。`sot.location_identifiers` で `location` の識別子を拠点に解決。`/orders/shipped/cancel` はこの出荷と単位を `status = cancelled` にする（`cancel_reason` = `reason`）
* 参照（read）: `sot.locations` / `sot.lm_location_priorities` / `sot.lm_sku_location_overrides` / `sot.lm_region_mappings` / `sot.channels` / `sot.products` / `sot.inventory_levels`

> 受注の **販売実績 SoT**（`sot.order_line_master`）とは分離した routing-native の identity（`source_system` + `external_order_ref` + `shipTo`）を持ちます。ルーティングは販売実績の取込とは独立して動作します。


---

# 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/routing-api/orders.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.
