> 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/operator-api/secure-scan.md).

# Secure Scan — 確保スキャン

店舗スタッフが商品ラベルの**ユニットQR**（`<barcode>|<shipmentId>`。出荷指示ラベルの本番印字形式）をスキャンして在庫を 1 ユニットずつ確保する API です。QR からの解決（`shipmentId` → 注文）と対象ユニットの選定をサーバ側で行うため、呼び出し側（picking-ios）は QR をそのまま渡すだけです。確保の進行で出荷元の全ユニットが確保済になると、shipment ヘッダを `secured` に遷移させ配送ラベルを自動生成します（[Units](/lmile-docs/fulfillment-api/units.md) の `POST /api/routing/secure` と同一経路）。

> **Base URL** `https://api.lmile.io` · **認証** operator JWT（`Authorization: Bearer`）または `x-ingest-secret` ヘッダー（[詳細](/lmile-docs/getting-started/authentication.md)） · `shop` はリクエストボディに含めます（API キーで呼ぶ場合は省略できます）

> **ユニットQR 規格**: `<barcode>|<shipmentId>`（`shipmentId` = `sot.lm_fulfillment_shipments.id`）。2 値は同一 barcode の複数ユニットを区別しないため、対象はサーバ側で「`status=allocated` かつ 未 picked の `lineInstanceNo` 昇順先頭 1 件」を選定します（スキャンのたびに次のユニットが確保されます）。

## エンドポイント

| Method | Path                        | 用途                                                | テーブル                                                                                                   |
| ------ | --------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `POST` | `/api/operator/secure-scan` | ユニットQR スキャンで 1 unit 確保（全確保でヘッダ `secured` + ラベル生成） | `lm_fulfillment_units` / `lm_fulfillment_shipments` / `lm_routing_orders` / `lm_shipping_instructions` |

***

## `POST` /api/operator/secure-scan

ユニットQR から対象ユニットを解決して確保（`status=secured` + `secured=true`）します。routingOrderId ベースで一括確保する [`POST /api/routing/secure`](/lmile-docs/fulfillment-api/units.md) のスキャン特化版で、確保のセマンティクス（ヘッダ遷移・ラベル生成・確保の非巻き戻し）は同一です。

### リクエスト

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

```json
{
  "shop": "demo-store.myshopify.com",
  "qr": "4912345678901|aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
}
```

### ボディパラメータ

| パラメータ  | 型      |  必須 | 説明                                          |
| ------ | ------ | :-: | ------------------------------------------- |
| `shop` | string |  ✓  | 店舗ドメイン（API キーで呼ぶ場合は省略できます）                  |
| `qr`   | string |  ✓  | ユニットQR（`<barcode>\|<shipmentId>`。最大 200 文字） |

### レスポンス

```json
{
  "ok": true,
  "routingOrderId": "7b1f08a3-1234-4abc-9def-0123456789ab",
  "shipmentId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "unitId": "uuuuuuuu-1111-2222-3333-444444444444",
  "lineInstanceNo": 1,
  "secured": 1,
  "alreadySecured": 0,
  "header": {
    "fromLocationId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "status": "secured",
    "trackingNumber": "499999999999",
    "labelPdfPath": "labels/demo-store.myshopify.com/....pdf",
    "labelStatus": "generated",
    "printStatus": "printed"
  },
  "orderFulfillmentStatus": "secured"
}
```

| フィールド                       | 説明                                                                                                                                                                                  |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `unitId` / `lineInstanceNo` | 今回確保したユニット（既確保の冪等応答では `unitId: null`）                                                                                                                                               |
| `secured`                   | 今回確保したユニット数（`1` または冪等応答の `0`）                                                                                                                                                       |
| `alreadySecured`            | shipment 配下の barcode 一致ユニットのうち既に確保済だった数                                                                                                                                             |
| `header`                    | 出荷元ヘッダの結果。全ユニット確保済になった場合は `secured` 遷移 + ラベル生成結果（`labelStatus`: `generated` / `skipped` / `failed`、`printStatus`: `printed` / `skipped` / `failed` / `none`）。まだ未確保ユニットが残る場合は `null` |
| `orderFulfillmentStatus`    | 注文全体の集約状態（`allocated` / `partially_secured` / `secured` / `oversell` / `shipped`）                                                                                                   |

### 挙動・冪等性

* **対象選定**: shipment 配下の barcode 一致ユニットから「`status=allocated` かつ 未 picked」を `lineInstanceNo` 昇順で先頭 1 件確保します。数量 2 なら 2 回のスキャンで全て確保されます。
* **ヘッダ遷移 + ラベル生成**: 確保によりヘッダ（出荷元 = 梱包単位）配下の全ユニットが確保済になると、ヘッダを `secured` に遷移させ [`POST /api/routing/secure`](/lmile-docs/fulfillment-api/units.md) と同一経路でラベルを生成します。ラベル失敗は `lastLabelError` に記録され、確保自体は巻き戻りません。
* **冪等**: 確保対象が無く既確保ユニットが居る再スキャンは `200` + `secured: 0` / `alreadySecured: N`（二重確保しません）。既に `secured` のヘッダはラベルを再生成しません。
* **operator 記録**: operator JWT 経由の確保は `secured_by_staff_user_id` に操作者（`auth.users.id`）を記録します。
* QR 不正形式は `422 invalid_qr`、旧規格は `422 legacy_qr`。`shipmentId` の shipment が無ければ `404 shipment_not_found`、barcode 一致 unit が無ければ `404 unit_not_found`。
* 確保可能でも既確保でもない（取消済 / 売越し / picked 済のみ等）場合は `409 unit_not_securable` で表面化します（fallback しません）。

## エラー

エンドポイント固有:

| Status | 条件                                                                                       | レスポンス例                                                                                                                       |
| :----: | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|  `422` | ユニットQR 形式不正                                                                              | \`{ "ok": false, "error\_kind": "invalid\_qr", "error": "unit QR must be                                                     |
|  `422` | 旧 mfc QR（受理せず再印刷を案内）                                                                     | \`{ "ok": false, "error\_kind": "legacy\_qr", "error": "legacy unit QR (JAN                                                  |
|  `404` | shipment が存在しない                                                                          | `{ "ok": false, "error_kind": "shipment_not_found", "error": "fulfillment shipment not found" }`                             |
|  `404` | barcode 一致 unit が存在しない                                                                   | `{ "ok": false, "error_kind": "unit_not_found", "error": "fulfillment unit not found" }`                                     |
|  `409` | 確保可能なユニットが無い（取消済 / 売越し / picked 済のみ等。`unitStatuses[]` に現状を同梱）                            | `{ "ok": false, "error_kind": "unit_not_securable", "error": "no securable unit (allocated & not picked) for barcode ..." }` |
|  `409` | ユニットが[倉庫間移動](/lmile-docs/transfer-api/batches.md)（出荷元変更）フロー中（行き先 / バルク所属を `units[]` に同梱） | `{ "ok": false, "error_kind": "transfer_required", "units": [...] }`                                                         |
|  `500` | shipment が指す注文の欠落（データ異常）                                                                 | `{ "ok": false, "error_kind": "data_inconsistency", "error": "routing_order not found for shipment ..." }`                   |

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

## データモデル

* `sot.lm_fulfillment_units` — [Units](/lmile-docs/fulfillment-api/units.md) の単位明細。本 API が `status` / `secured` / `secured_at` / `secured_by_staff_user_id` を更新します。
* `sot.lm_fulfillment_shipments` — 出荷元ヘッダ（梱包単位）。全ユニット確保で `secured` 遷移 + 追跡番号 / ラベル列を更新します。
* `sot.lm_shipping_instructions` — 保存済み出荷指示（ラベル生成時の明細 / 配送先の出所）。


---

# 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/operator-api/secure-scan.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.
