> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 受信者を追加

> ストアのマーチャント通知メールを受け取るアドレスを追加する

ストアにマーチャント通知の受信者を追加します。各ストアの受信者は最大 **5 件**です。新規受信者の 9 つのイベントトグルは**ストア側の現在の `notify*` 設定を継承**し（ストアが未設定のキーは購読として扱われます）、`isPrimary` は常に `false` です。既にオフにしたイベントが、受信者の追加によって再開することはありません。

継承が起きるのは**作成時の一度だけ**です：9 つのキーはその時点で書き込まれるため、以降ストアの `notify*` を変更しても既存の受信者には反映されません（変更は `update-recipient` で行います）。同様に、2 人目の受信者は 1 人目の選択ではなくストアの現在値を継承し、削除したアドレスを再追加した場合も以前の設定の復元ではなく新たな継承になります。

<Warning>
  明示的な受信者が 1 件もない間、リストには合成されたフォールバックエントリ（`isPrimary: true`）が表示され、アドレスはストアオーナーのアカウントメールで、通知もそこへ届きます。**最初の明示的な受信者を追加するとそのフォールバックは消えます** —— 以降は設定されたアドレスのみが通知を受け取ります。
</Warning>

```
POST /v1/actions/store-notification-recipient/add-recipient
```

**認証：** API Key（owner または admin ロールが必要）

## リクエストボディ

| フィールド     | 型      | 必須 | 説明                                                                           |
| --------- | ------ | -- | ---------------------------------------------------------------------------- |
| `storeId` | string | はい | ストア ID（Short ID 形式 `STO_xxx`）                                                |
| `email`   | string | はい | 受信アドレス。保存前に `lower(trim())` で正規化されるため、大文字小文字や前後の空白だけが異なるアドレスは同一の受信者として扱われます。 |

## リクエスト例

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X POST https://api.waffo.com/v1/actions/store-notification-recipient/add-recipient \
    -H "Content-Type: application/json" \
    -H "X-Merchant-Id: $WAFFO_MERCHANT_ID" \
    -H "X-Signature: ..." \
    -d '{
      "storeId": "STO_2aUyqjCzEIiEcYMKj7TZtw",
      "email": "ops@acme.com"
    }'
  ```

  ```javascript JavaScript theme={"system"}
  const response = await fetch(
    "https://api.waffo.com/v1/actions/store-notification-recipient/add-recipient",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Merchant-Id": process.env.WAFFO_MERCHANT_ID,
        "X-Signature": signature,
      },
      body: JSON.stringify({
        storeId: "STO_2aUyqjCzEIiEcYMKj7TZtw",
        email: "ops@acme.com",
      }),
    },
  );

  const { data } = await response.json();
  ```
</CodeGroup>

## 成功レスポンス (200)

```json theme={"system"}
{
  "data": {
    "recipient": {
      "id": "11111111-2222-3333-4444-555555555555",
      "storeId": "STO_2aUyqjCzEIiEcYMKj7TZtw",
      "email": "ops@acme.com",
      "isPrimary": false,
      "preferences": {
        "notifyNewOrders": true,
        "notifyNewSubscriptions": true,
        "notifySubscriptionCanceled": true,
        "notifySubscriptionRenewed": true,
        "notifySubscriptionEnded": true,
        "notifySubscriptionPastDue": true,
        "notifySubscriptionUncanceled": true,
        "notifySubscriptionPlanChanged": true,
        "notifyChargeback": true
      },
      "createdAt": "2026-08-28T00:00:00.000Z"
    }
  }
}
```

<Note>
  返される `recipient.id` は Short ID ではなく UUID です。不透明な文字列として扱い、`update-recipient` と `remove-recipient` の `recipientId` にそのまま渡してください。
</Note>

## レスポンスフィールド

| フィールド         | 型       | 説明                                                     |
| ------------- | ------- | ------------------------------------------------------ |
| `id`          | string  | 受信者 UUID。フォールバックエントリは `OWNER_<storeId>` 形式のセンチネル値を使います |
| `storeId`     | string  | 所属ストアの Short ID                                        |
| `email`       | string  | 正規化された受信アドレス                                           |
| `isPrimary`   | boolean | 本エンドポイントで追加した受信者は常に `false`。合成されたフォールバックエントリのみが `true` |
| `preferences` | object  | 9 つのイベントトグル。作成時にストアの現在の `notify*` を継承                  |
| `createdAt`   | string  | 作成日時（ISO 8601）                                         |

## エラー

> **リトライ方針：** 4xx は決してリトライしないでください —— リクエストを修正して再送します。5xx は指数バックオフでリトライします（初回 5 秒、最大 3 回）。

| ステータス | `errors[0].message`                                               | 意味                                   | 推奨対応                        |
| ----- | ----------------------------------------------------------------- | ------------------------------------ | --------------------------- |
| 400   | `Missing required field: storeId`                                 | `storeId` が未指定                       | リクエストボディを修正して再送             |
| 400   | `Expected format: STO_xxx, got "..."`                             | `storeId` の Short ID をデコードできない       | `storeId` の形式を修正して再送        |
| 400   | `Invalid email format`                                            | `email` が正しいアドレスではない                 | アドレスを修正して再送                 |
| 400   | `Notification recipient limit reached (max 5 per store)`          | ストアに既に 5 件の受信者がある                    | 既存の受信者を先に削除                 |
| 401   | `Missing merchantId in request context`                           | API Key 認証でマーチャントを解決できなかった           | API Key のヘッダーと署名を確認         |
| 403   | `Not authorized to manage notification recipients for this store` | マーチャントがそのストアの `owner` / `admin` ではない | ストアにおけるマーチャントのロールを確認        |
| 409   | `Recipient with this email already exists for this store`         | 正規化後のアドレスが既に受信者として存在、または並行書き込みが先行    | 重複追加せず既存の受信者を更新             |
| 500   | `Internal server error`                                           | サーバー側の予期しない障害                        | 指数バックオフでリトライ（初回 5 秒、最大 3 回） |
