> 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/ingestion-api/share-analytics.md).

# Share Analytics — 店舗→EC送客

店舗スタッフが顧客へ商品を共有（LINE / メール / QR）した**送客データ**（共有・共有商品・追跡イベント）を batch で投入します。送信元システムは `source`（slug）で識別し、`sot.lm_share_analytics_shares` / `_items` / `_events` に冪等 upsert します。結合キーは送信元の行 id（`source_share_id` / `source_item_id` / `source_event_id`）です。

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

> **PII 遮断**: raw の共有トークン・スタッフメール・LINE ユーザー id・顧客 id は**保存されません**。受信時に HMAC-SHA-256 で hash 化され、hash 列のみ保存します。`payload` も PII キー（`lineUserId` / `displayName` / `email` / `phoneNumber` / 氏名系 等）を strip した残りだけが保存されます。

## エンドポイント

| Method | Path                          | 用途                                 | テーブル                                               |
| ------ | ----------------------------- | ---------------------------------- | -------------------------------------------------- |
| `POST` | `/api/ingest/share-analytics` | 送客の共有・商品・イベントを batch 投入（冪等 upsert） | `lm_share_analytics_shares` / `_items` / `_events` |

***

## `POST` /api/ingest/share-analytics

`shares` / `items` / `events` の 3 配列を任意の組み合わせで送信します（**少なくとも 1 つ必須**・各配列 1,000 件まで）。テーブル間に FK は張っていないため、イベントが親 share より先に着弾しても安全です（分割送信・並行送信可）。

### リクエスト

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

```json
{
  "shop": "demo-store.myshopify.com",
  "source": "theme-main",
  "shares": [
    {
      "source_share_id": "cshr01hxx0001",
      "source_share_token": "raw-share-token-uuid",
      "touchpoint": "line",
      "store_code": "loc-ginza-01",
      "store_name": "銀座店",
      "staff_customer_id": "7001234567890",
      "staff_display_name": "山田太郎",
      "staff_email": "yamada@example.com",
      "utm_source": "store",
      "utm_medium": "line",
      "utm_campaign": "loc-ginza-01",
      "expires_at": "2026-08-01T00:00:00.000Z",
      "created_at_source": "2026-07-01T02:30:00.000Z",
      "updated_at_source": "2026-07-01T02:30:00.000Z"
    }
  ],
  "items": [
    {
      "source_share_id": "cshr01hxx0001",
      "source_item_id": "citm01hxx0001",
      "shopify_product_id": "8000000000001",
      "shopify_variant_id": "44000000000001",
      "product_title_snapshot": "レザートートバッグ",
      "variant_title_snapshot": "ブラック",
      "price_snapshot": 41800,
      "qty": 1,
      "image_url": "https://cdn.shopify.com/..."
    }
  ],
  "events": [
    {
      "source_event_id": "cevt01hxx0001",
      "source_share_id": "cshr01hxx0001",
      "event_type": "purchased",
      "occurred_at": "2026-07-01T10:00:00.000Z",
      "order_id": "6066867601541",
      "line_user_id": "U4af4980629...",
      "payload": { "totalPrice": "41800", "currency": "JPY" }
    }
  ]
}
```

### ボディパラメータ

| パラメータ    | 型      |  必須 | 説明                                                                    |
| -------- | ------ | :-: | --------------------------------------------------------------------- |
| `shop`   | string |     | 店舗ドメイン（省略するとキーのアカウント）                                                 |
| `source` | string |  ✓  | 送信元システムの slug（`[a-z0-9_-]`・最大 50 文字。例 `theme-main`）。冪等 upsert キーの一部   |
| `shares` | array  |     | 共有（送客）の配列（最大 1,000 件）                                                 |
| `items`  | array  |     | 共有商品スナップショットの配列（最大 1,000 件）                                           |
| `events` | array  |     | 追跡イベントの配列（最大 1,000 件）。`shares` / `items` / `events` の**少なくとも 1 つが必須** |

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

| パラメータ                                                        | 型                 |  必須 | 説明                                                        |
| ------------------------------------------------------------ | ----------------- | :-: | --------------------------------------------------------- |
| `source_share_id`                                            | string            |  ✓  | 送信元の共有 id（`source` との組で一意）                                |
| `source_share_token`                                         | string            |  ✓  | 共有リンクの raw トークン。**受信時に hash 化され raw は保存されません**（欠落行は skip） |
| `touchpoint`                                                 | string            |     | 共有手法（`line` / `email` / `qr` 等。省略時 `unknown`）             |
| `store_code`                                                 | string            |  ✓  | 送客元店舗のコード                                                 |
| `store_name`                                                 | string            |     | 店舗表示名スナップショット                                             |
| `staff_customer_id`                                          | string            |  ✓  | 共有したスタッフの業務 id                                            |
| `staff_display_name`                                         | string            |     | スタッフ氏名スナップショット（社内 dashboard 表示用・外部 API 非公開）               |
| `staff_email`                                                | string            |     | スタッフメール。**受信時に hash 化され raw は保存されません**                    |
| `utm_source` / `utm_medium` / `utm_campaign` / `utm_content` | string            |     | 送客リンクの UTM                                                |
| `expires_at`                                                 | string (ISO 8601) |     | 共有リンクの有効期限                                                |
| `created_at_source` / `updated_at_source`                    | string (ISO 8601) |  ✓  | 送信元での作成・更新時刻                                              |
| `metadata`                                                   | object            |     | 追加メタデータ（PII キーは strip して保存）                               |

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

| パラメータ                                               | 型       |  必須 | 説明                          |
| --------------------------------------------------- | ------- | :-: | --------------------------- |
| `source_share_id`                                   | string  |  ✓  | 親共有の送信元 id                  |
| `source_item_id`                                    | string  |  ✓  | 送信元の商品行 id（`source` との組で一意） |
| `shopify_product_id` / `shopify_variant_id`         | string  |     | Shopify 商品/バリアント id（数値 id）  |
| `sku`                                               | string  |     | SKU                         |
| `product_title_snapshot` / `variant_title_snapshot` | string  |     | 共有時点の商品名/バリアント名             |
| `price_snapshot`                                    | number  |     | 共有時点の価格                     |
| `qty`                                               | integer |     | 数量（省略・不正値は `1`）             |
| `image_url`                                         | string  |     | 商品画像 URL                    |

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

| パラメータ             | 型                 |  必須 | 説明                                                                                                                                  |
| ----------------- | ----------------- | :-: | ----------------------------------------------------------------------------------------------------------------------------------- |
| `source_event_id` | string            |  ✓  | 送信元のイベント id（`source` との組で一意）                                                                                                        |
| `source_share_id` | string            |  ✓  | 親共有の送信元 id                                                                                                                          |
| `event_type`      | string            |  ✓  | `opened` / `line_pushed` / `line_liff_opened` / `product_click` / `add_to_cart` / `purchased` のみ（それ以外は `unknown_event_type` で skip） |
| `occurred_at`     | string (ISO 8601) |  ✓  | 発生時刻（60 秒超の未来時刻は `invalid_occurred_at` で skip）                                                                                      |
| `order_id`        | string            |     | 購入イベントの注文 id。hash 列に加え、売上突合用の internal-only 参照列（外部 API 非公開）にも保持します                                                                  |
| `line_user_id`    | string            |     | LINE ユーザー id。**受信時に hash 化され raw は保存されません**                                                                                         |
| `customer_id`     | string            |     | 顧客 id。**受信時に hash 化され raw は保存されません**                                                                                                |
| `payload`         | object            |     | イベント付随データ（PII キーは strip して保存）                                                                                                       |

### レスポンス

```json
{
  "ok": true,
  "shares": { "received": 1, "processed": 1, "skipped": [], "errors": [] },
  "items":  { "received": 1, "processed": 1, "skipped": [], "errors": [] },
  "events": { "received": 1, "processed": 1, "skipped": [], "errors": [] }
}
```

| フィールド       | 説明                                                                       |
| ----------- | ------------------------------------------------------------------------ |
| `received`  | 受信した行数                                                                   |
| `processed` | upsert に成功した行数                                                           |
| `skipped`   | 行単位で skip した行（`{ reason, source_id }`。silent skip しません）                  |
| `errors`    | upsert 失敗（`{ code: "upsert_failed" }`。1 件でもあると HTTP `207` / `ok: false`） |

### 挙動・冪等性

* **解決キー**: `source + source_share_id`（shares）/ `source + source_item_id`（items）/ `source + source_event_id`（events）の UNIQUE への upsert。同一行の再送・backfill 重複に冪等です。
* **PII sanitize**: `source_share_token` / `staff_email` / `line_user_id` / `customer_id` / `order_id` は受信時に HMAC-SHA-256 hash 化して保存し、raw は保持しません（`order_id` のみ売上突合用の internal-only 参照列を別途保持）。`metadata` / `payload` は PII キーを strip した残りのみ保存します。
* **行単位 skip**: 必須欠落（`missing_required_field`）・許可外イベント種別（`unknown_event_type`）・不正/未来時刻（`invalid_occurred_at`）・トークン欠落（`missing_share_token_or_hash_secret`）は該当行のみ `skipped[]`（reason 付き）で返し、他の行の処理は継続します。
* **部分失敗**: テーブル単位の upsert 失敗は `errors[]` に収集し HTTP `207` で返します（成功したテーブルはそのまま反映）。
* **順序非依存**: shares / items / events 間に FK が無いため、分割送信でイベントが先に届いても失敗しません。

## エラー

エンドポイント固有:

| Status | 条件                                              | レスポンス例                                                                             |
| :----: | ----------------------------------------------- | ---------------------------------------------------------------------------------- |
|  `400` | `source` 欠落・slug 形式外                            | `{ "ok": false, "error": "source required (slug: [a-z0-9_-], max 50)" }`           |
|  `400` | `shares` / `items` / `events` がいずれも空            | `{ "ok": false, "error": "at least one of shares / items / events required" }`     |
|  `400` | 配列が 1,000 件超                                    | `{ "ok": false, "error": "max 1000 shares per request" }`                          |
|  `503` | サーバー側 hash secret 未設定（全行 skip を成功に見せないための明示エラー） | `{ "ok": false, "error": "LM_SHARE_HASH_SECRET not configured" }`                  |
|  `207` | 一部テーブルの upsert 失敗（部分反映）                         | `{ "ok": false, "shares": { ..., "errors": [{ "code": "upsert_failed" }] }, ... }` |

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

## データモデル

* `sot.lm_share_analytics_shares` — 送客の共有 1 件 = 1 行。トークン・スタッフメールは hash 列のみ（`UNIQUE (source, source_share_id)`）
* `sot.lm_share_analytics_items` — 共有商品スナップショット（`UNIQUE (source, source_item_id)`）
* `sot.lm_share_analytics_events` — 追跡イベント（開封 / LINE push / LIFF 開封 / 商品クリック / カート追加 / 購入。`UNIQUE (source, source_event_id)`）

3 テーブルとも service\_role 専用で、`agent_read.*` には公開していません（公開時は PII 遮断設計を別途行います）。


---

# 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/ingestion-api/share-analytics.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.
