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

# Customer Orders — 顧客注文照会

メールアドレスを突合キーに、その顧客の注文履歴と出荷ステータスを返す read API です。マイページ・注文照会画面などの BFF（アプリのサーバー側）から server-to-server で呼び出す想定です。突合キーは [Routing](/lmile-docs/routing-api/orders.md)（`/api/routing/orders`）で受け付けた注文の `shipTo.email`（`sot.lm_routing_orders`）で、明細・金額は `sot.order_line_master` を `transaction_id` = `externalOrderRef` の先頭（`-` より前）で結合して集計します。1 つの買い物が複数の受注レコードに分かれていても（刻印の `-engraved` / 出荷元の分割 / 予約分）、同じ取込元・同じ注文番号（`orderName`）のレコードは **1 注文にまとめて**返します。

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

## エンドポイント

| Method | Path                          | 用途                              | テーブル                                                                   |
| ------ | ----------------------------- | ------------------------------- | ---------------------------------------------------------------------- |
| `POST` | `/api/customer-orders/list`   | 注文一覧（ページネーション付き）                | `lm_routing_orders` / `lm_fulfillment_shipments` / `order_line_master` |
| `POST` | `/api/customer-orders/detail` | 注文詳細（明細 / 金額 / 配送先 / 出荷元別ステータス） | 上記 + `lm_fulfillment_units` / `products`                               |

> read API ですが `email` を query string に載せない（アクセスログへの PII 漏洩防止）ため **POST** です。レスポンスは camelCase（routing 系と同じ）。
>
> **前提**: 対象になるのは [Routing](/lmile-docs/routing-api/orders.md) に **`shipTo.email` 付きで投入された注文**だけです。email なしで投入された注文・routing を通っていない注文は返りません。また金額・明細の結合には、[Order Line Master](/lmile-docs/ingestion-api/order-line-master.md) の `transaction_id` と routing の `externalOrderRef` の先頭（`-` より前）が**同一の注文識別子**で投入されている必要があります（突合できない注文は `total` / `amounts` が `null` になります）。

### 集約ステータス（`status`）

注文全体のステータスは出荷元（shipment）単位のステータスから次の 4 値に集約します。配達完了（delivered）はキャリアの配達イベントを持たないため**存在しません**（終端は `shipped`）。

| 判定順 | 条件                                     | `status`            |
| :-: | -------------------------------------- | ------------------- |
|  1  | 注文が取消済（または全出荷元が `cancelled`）           | `cancelled`         |
|  2  | 全出荷元が出荷完了                              | `shipped`           |
|  3  | 一部の出荷元のみ出荷完了                           | `partially_shipped` |
|  4  | それ以外（受付済 / 引き当て済 / 確保済 / 梱包中 / 在庫不足 等） | `processing`        |

### 注文ステータス（`shipments[].orderStatus`）

出荷元（shipment）ごとの、購入者向けの注文ステータスです（お届け状況ページ・メール・管理画面のバッジと同じ 11 値）。`status` が出荷元の工程から集約した 4 値なのに対し、こちらは出荷元ごとの値をそのまま返します。

| `orderStatus`                           | 意味                      |
| --------------------------------------- | ----------------------- |
| `received`                              | 受注                      |
| `on_hold_customer` / `on_hold_internal` | 保留（お客様側 / 社内側）          |
| `preparing`                             | 準備中                     |
| `in_transfer`                           | 転送中（拠点間を移動中）            |
| `shipped` / `in_transit` / `delivered`  | 出荷済 / 配送中 / 配達完了（配送の荷物） |
| `ready_for_pickup` / `picked_up`        | 受取待ち / 引渡し済み（店舗受け取りの荷物） |
| `cancelled`                             | キャンセル                   |

***

## `POST` /api/customer-orders/list

メールアドレスに紐づく注文の一覧を新しい順（受付日時 降順）に返します。1 行 = 1 つの買い物です（複数の受注レコードに分かれた注文は 1 行にまとめ、`totalCount` もまとめた後の数です）。

### リクエスト

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

```json
{
  "shop": "demo-store.myshopify.com",
  "email": "taro@example.com",
  "limit": 20,
  "cursor": null
}
```

### ボディパラメータ

| パラメータ    | 型      |  必須 | 説明                                  |
| -------- | ------ | :-: | ----------------------------------- |
| `shop`   | string |     | 店舗識別子（省略するとキーのアカウント）                |
| `email`  | string |  ✓  | 顧客メールアドレス。大文字小文字・前後空白は無視して突合        |
| `limit`  | number |     | 1 ページの件数。既定 `20`・最大 `50`            |
| `cursor` | string |     | 前ページの `pageInfo.endCursor`。省略で先頭ページ |

### レスポンス

```json
{
  "ok": true,
  "totalCount": 12,
  "orders": [
    {
      "id": "0d9e2f64-...",
      "orderNumber": "BJP1001",
      "externalOrderRef": "6297646694533",
      "sourceSystem": "shopify",
      "orderedAt": "2026-05-12T09:15:00+09:00",
      "status": "shipped",
      "itemCount": 2,
      "total": 12990,
      "currency": "JPY",
      "thumbnailUrl": "https://cdn.example.com/products/123.jpg",
      "shipments": [
        { "id": "7c1a9b22-...", "orderStatus": "shipped" }
      ],
      "items": [
        {
          "barcode": "1234567890123",
          "sku": "TOTE-BK-M",
          "productName": "Mizuki Leather Tote",
          "variantName": "Black / M",
          "quantity": 2,
          "unitPrice": 5995,
          "imageUrl": "https://cdn.example.com/products/123.jpg"
        }
      ]
    }
  ],
  "pageInfo": { "hasNextPage": true, "endCursor": "eyJjIjoi..." }
}
```

| フィールド                         | 説明                                                                                                                                                         |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `totalCount`                  | この email に紐づく注文の総数（ページに依らず全件。まとめた後の数）                                                                                                                      |
| `orders[].id`                 | 注文 ID（`lm_routing_orders.id`。まとめた注文は最初に作られた受注レコードの ID）。詳細取得（`detail`）に渡す                                                                                   |
| `orders[].orderNumber`        | 注文番号（routing の `orderName`。例 `BJP1001`）。無い場合は `externalOrderRef`                                                                                           |
| `orders[].externalOrderRef`   | カート側の注文識別子（routing の `externalOrderRef`。まとめた注文は最初に作られた受注レコードの値）                                                                                            |
| `orders[].orderedAt`          | 受注日時（`order_line_master.ordered_at`。突合できない場合は routing 受付日時）                                                                                                |
| `orders[].status`             | [集約ステータス](#集約ステータスstatus)（4 値。まとめた受注レコード全体の出荷元で判定）                                                                                                         |
| `orders[].itemCount`          | 購入点数（per-unit 行数から返金した点数を引いた数）。`order_line_master` と突合できない場合 `null`                                                                                        |
| `orders[].total` / `currency` | 合計（税込・値引/返金考慮前の `net` 合算）。突合できない場合 `null`                                                                                                                  |
| `orders[].thumbnailUrl`       | 先頭明細の商品画像（`products.primary_image_url`）。未登録は `null`                                                                                                        |
| `orders[].items[]`            | 明細を `barcode` 単位に集約（`detail` の `items[]` と同じ形）。商品名は商品マスターの値。突合できない注文は `[]`                                                                                 |
| `orders[].shipments[]`        | 出荷元（梱包）ごとの `id`（`detail` の `shipments[].id` と同じ）と[注文ステータス](#注文ステータスshipmentsorderstatus) `orderStatus`。まとめた受注レコード全部の出荷元（転送先で顧客へ出荷するレグも含む）。出荷元がまだ無い注文は `[]` |
| `pageInfo`                    | keyset カーソル。`hasNextPage: true` なら `endCursor` を次リクエストの `cursor` に渡す                                                                                       |

### 挙動

* 該当注文が無い email は **`200` + `orders: []`**（email の存在判定をさせない）。
* 1 つの買い物が複数の受注レコードに分かれていても（刻印の `-engraved` / 出荷元の分割 `-{拠点}` / 予約分 `-p.{key}`）、同じ取込元・同じ `orderName` のレコードは 1 行にまとめます。`orderName` が無い受注は `externalOrderRef` の先頭（`-` より前）でまとめます。転送先で顧客へ出荷するためだけの受注レコードは行にせず、元の注文の出荷元として数えます。
* `status` でのサーバー側フィルタは未対応です（ページ内をクライアント側でフィルタしてください）。

***

## `POST` /api/customer-orders/detail

注文 1 件の明細・金額・配送先・出荷元別の出荷ステータスを返します。`email` と注文の組み合わせが**所有権チェック**になっており、email が一致しない注文 ID は存在しない扱い（`404`）になります。

### リクエスト

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

```json
{
  "shop": "demo-store.myshopify.com",
  "email": "taro@example.com",
  "orderId": "0d9e2f64-..."
}
```

### ボディパラメータ

| パラメータ     | 型             |  必須 | 説明                    |
| --------- | ------------- | :-: | --------------------- |
| `shop`    | string        |     | 店舗識別子（省略するとキーのアカウント）  |
| `email`   | string        |  ✓  | 顧客メールアドレス（所有権チェックに使用） |
| `orderId` | string (uuid) |  ✓  | `list` が返した注文 ID      |

### レスポンス

```json
{
  "ok": true,
  "order": {
    "id": "0d9e2f64-...",
    "orderNumber": "BJP1001",
    "externalOrderRef": "6297646694533",
    "sourceSystem": "shopify",
    "orderedAt": "2026-05-12T09:15:00+09:00",
    "status": "shipped",
    "items": [
      {
        "barcode": "1234567890123",
        "sku": "TOTE-BK-M",
        "productName": "Mizuki Leather Tote",
        "variantName": "Black / M",
        "quantity": 2,
        "unitPrice": 5995,
        "imageUrl": "https://cdn.example.com/products/123.jpg"
      }
    ],
    "amounts": {
      "subtotal": 11990,
      "discount": 0,
      "tax": 1090,
      "refund": 0,
      "total": 11990,
      "shipping": null,
      "currency": "JPY"
    },
    "shippingAddress": {
      "name": "山田 太郎",
      "company": null,
      "phone": "+819012345678",
      "email": "taro@example.com",
      "country": "JP",
      "postalCode": "150-0001",
      "prefecture": "東京都",
      "city": "渋谷区",
      "address1": "道玄坂1-2-3",
      "address2": "○○ビル 4F"
    },
    "shipments": [
      {
        "id": "7c1a9b22-...",
        "fromLocationId": "a1b2c3d4-...",
        "locationLabel": "MFCセンター東京",
        "status": "shipped",
        "orderStatus": "shipped",
        "carrierCode": "yamato",
        "trackingNumber": "1234-5678-9012",
        "shippedAt": "2026-05-13T18:00:00+09:00",
        "cancelledAt": null
      }
    ],
    "timeline": {
      "orderedAt": "2026-05-12T09:15:00+09:00",
      "shippedAt": "2026-05-13T18:00:00+09:00",
      "cancelledAt": null
    }
  }
}
```

| フィールド                              | 説明                                                                                                                                                                                                                                                         |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `orderNumber` / `externalOrderRef` | `list` と同じ（注文番号 / カート側の注文識別子）。`orderId` がまとめた受注レコードのどれでも、同じ買い物として明細・出荷元をまとめて返す                                                                                                                                                                             |
| `items[]`                          | `order_line_master` の per-unit 行を `barcode` 単位に集約。`quantity` = 行数から返金した点数を引いた数（全部返金した商品は含まない）、`unitPrice` = 税込単価（`gross_amount_taxincl`）。商品名は注文明細に書かれていた名前（注文時点・注文したストアの言語）を優先し、無ければ `products` を barcode で結合（未登録は `null`）                                 |
| `amounts`                          | `order_line_master` の合算（`subtotal` = 税込定価合計 / `discount` = 値引合計（正の値） / `tax` = 内税合計 / `refund` = 返金済合計 / `total` = 税込支払合計）。**`shipping` は SoT に送料を持たないため常に `null`**。突合できない注文は `amounts` 全体が `null`（`items` は fulfillment 単位に fallback し `unitPrice: null`） |
| `shippingAddress`                  | routing の `shipTo`（[住所修正](/lmile-docs/fulfillment-api/address-recovery.md)が反映された最新値）                                                                                                                                                                       |
| `shipments[]`                      | 出荷元（梱包）単位のステータス・[注文ステータス](#注文ステータスshipmentsorderstatus)（`orderStatus`）・キャリア・追跡番号。複数拠点から分割出荷される場合は複数行                                                                                                                                                       |
| `timeline.shippedAt`               | **全出荷元の出荷完了時のみ**設定（`max(shipped_at)`）。一部出荷の途中経過は `shipments[]` を参照                                                                                                                                                                                         |
| `timeline`                         | 配達完了（deliveredAt）は持ちません（[集約ステータス](#集約ステータスstatus)参照）                                                                                                                                                                                                       |

> 決済手段（カードブランド等）は LMile の SoT に存在しないため返しません。

## エラー

エンドポイント固有:

| Status | 条件                                                   | レスポンス                                                                          |
| :----: | ---------------------------------------------------- | ------------------------------------------------------------------------------ |
|  `400` | `email` 欠落・形式不正 / `orderId` が uuid でない / `cursor` 不正 | `{ "ok": false, "error": "invalid email" }` 等                                  |
|  `404` | 注文が存在しない、**または email が注文の宛先と一致しない**（存在を判別させない）       | `{ "ok": false, "error_kind": "order_not_found", "error": "order not found" }` |

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

## データモデル

* `sot.lm_routing_orders` — 突合キー `ship_to_email`（正規化生成列 `ship_to_email_norm` で検索）。注文ヘッダ・配送先
* `sot.lm_fulfillment_shipments` — 出荷元単位のステータス・追跡番号・出荷日時
* `sot.lm_fulfillment_units` — 明細 fallback（`order_line_master` と突合できない注文）
* `sot.order_line_master` — 明細・金額の正（`shop + source_system + transaction_id` = `externalOrderRef` の先頭（`-` より前）で結合）
* `sot.products` — 商品名 / バリアント名 / 画像（barcode 結合）

read 専用 API のため SoT への書き込みはありません（[Idempotency](/lmile-docs/reference/idempotency.md)）。


---

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