L

APIリファレンス

友だち・タグ・メッセージ・予約・Webhook購読をRESTで操作できます。Zapier連携もこのAPIの上に構築されています。

Base URL: https://l.oku-ai.co.jp/api/v1

認証

すべてのリクエストにAPIキーが必要です。キーはLokuダッシュボードの 開発者 > APIキー で発行します (発行は無料)。実データの読み書きは、対象プロジェクトのプランがProプラン以上のときに有効になります。 発行時にスコープ (権限) を選択でき、キーはリクエストに必要な最小のスコープだけを持つことを推奨します。

curl https://l.oku-ai.co.jp/api/v1/friends?limit=1 \
  -H "Authorization: Bearer lk_xxxxxxxxxxxxxxxx"

キーが無効・期限切れ・プラン要件未達の場合は 401 を返します。スコープ不足は 403 です。

共通仕様

IDすべてのIDは26文字のULIDです (例: 01ARZ3NDEKTSV4RRFFQ69G5FAV)。
レート制限300リクエスト/分。超過時は 429 を返します。IPとAPIキーの両方で計測します。
冪等性POST /messages POST /reservations Idempotency-Key ヘッダが必須です (英数字と _ - で1–255文字)。同じキーでの再送は初回の結果を再生し、二重送信・二重予約を防ぎます。
命名規約予約 (reservations) とWebhook購読 (webhook_endpoints) のレスポンスは snake_case、それ以外のリソースは camelCase です。各エンドポイントのレスポンス例が正です。
日時ISO 8601 (UTC) の文字列です。日付のみの項目は YYYY-MM-DD です。

友だち (Friends)

LINE公式アカウントの友だち。CRMの中心となるリソースです。

GET/friends

友だちの一覧を取得します (作成日時の降順)。

スコープ: friends:read

クエリパラメータ

pageintegerページ番号 (既定 1)
limitinteger1ページの件数 (1–100、既定 20)
searchstring表示名の部分一致
statusstringfollowing | blocked | unfollowed

レスポンス例

{
  "data": [
    {
      "id": "01ABC...",
      "lineUserId": "U1234...",
      "displayName": "山田 太郎",
      "pictureUrl": "https://...",
      "status": "following",
      "score": 82,
      "followedAt": "2026-07-01T00:00:00.000Z",
      "lastMessageAt": "2026-07-10T09:30:00.000Z",
      "messageCount": 12,
      "createdAt": "2026-07-01T00:00:00.000Z"
    }
  ],
  "pagination": { "page": 1, "limit": 20, "total": 152, "totalPages": 8 }
}

主なエラー

401UnauthorizedAPIキーが無効・期限切れ・プラン要件未達
403Insufficient scopefriends:read が付与されていない
429リクエストが多すぎますレート制限超過
GET/friends/{id}/external-ids

友だちに紐づく外部IDの一覧を取得します。

スコープ: friends:read

レスポンス例

{
  "data": [
    {
      "id": "01XID...",
      "friendId": "01ABC...",
      "namespace": "shopify",
      "externalId": "cus_12345",
      "source": "api",
      "createdAt": "2026-07-01T00:00:00.000Z",
      "updatedAt": "2026-07-01T00:00:00.000Z"
    }
  ]
}

主なエラー

400invalid friend idid が26文字のULIDでない
404friend not found友だちが存在しない (他テナント含む)

タグ (Tags)

タグはセグメント配信・シナリオ自動化の起点です。外部イベント→タグ付与が基本パターンです。

GET/tags

タグの一覧を取得します。

スコープ: tags:read

クエリパラメータ

limitinteger件数 (最大 500、既定 100)
offsetintegerオフセット (既定 0)

レスポンス例

{
  "data": [
    { "id": "01TAG...", "name": "VIP", "color": "#06C755", "createdAt": "2026-06-01T00:00:00.000Z" }
  ],
  "hasMore": false,
  "limit": 100,
  "offset": 0
}

主なエラー

403Insufficient scopetags:read が付与されていない
POST/tags

友だちにタグを付与または解除します。付与時はシナリオトリガー・リッチメニュー出し分けが自動で再評価されます。

スコープ: tags:write

リクエストボディ (JSON)

friendId必須string友だちID (ULID)
tagId必須stringタグID (ULID)
action必須stringadd | remove

レスポンス例

{ "success": true, "action": "added" }

主なエラー

400friendId, tagId, and action (add/remove) are required必須フィールド欠如・action不正
404Friend not found / Tag not found対象が存在しない

メッセージ (Messages)

友だちへのLINEメッセージ送信。月次のメッセージ配信枠を消費します。

POST/messages

テキストメッセージを送信します (最大5通/リクエスト)。

スコープ: messages:writeヘッダ: Idempotency-Key 必須

リクエストボディ (JSON)

friendId必須string友だちID (ULID)。status=following のみ送信可
messages必須array{ type: "text", text: string } の配列 (1–5件、text 最大5,000文字)

レスポンス例

{ "success": true }

同じ Idempotency-Key での再送は初回の結果を再生します (レスポンスに idempotent_replay: true が付きます)。

主なエラー

400Friend is not following友だちがブロック中・解除済み
400Idempotency-Key header is requiredヘッダ欠如
409Request with same Idempotency-Key is already in-flight同キーの処理が進行中
429Monthly message quota exceeded月次メッセージ枠を超過 (remaining を含む)

予約 (Reservations)

予約の作成・取得。一覧はカーソル方式 (Stripe互換のlist形式) です。レスポンスは snake_case です。

GET/reservations

予約の一覧を取得します (新しい順)。

スコープ: reservations:read

クエリパラメータ

friendIdstring友だちIDで絞り込み (ULID)
eventIdstring予約イベントIDで絞り込み (ULID)
statusstringpending | confirmed | canceled | no_show | completed | cancel_requested
from / tostring予約日の範囲 (YYYY-MM-DD)
limitinteger件数 (1–100、既定 50)
starting_afterstringカーソル (前ページ末尾の id)

レスポンス例

{
  "object": "list",
  "data": [
    {
      "id": "01RESV...",
      "event_id": "01EVT...",
      "slot_id": "01SLOT...",
      "friend_id": "01ABC...",
      "status": "confirmed",
      "payment_status": "not_required",
      "reservation_date": "2026-07-20",
      "start_time": "14:00",
      "end_time": "15:00",
      "number_of_guests": 1,
      "staff_id": null,
      "note": null,
      "canceled_at": null,
      "created_at": "2026-07-14T02:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

主なエラー

400status must be one of: ...クエリの形式不正
GET/reservations/{id}

予約を1件取得します。

スコープ: reservations:read

レスポンス例

{
  "id": "01RESV...",
  "event_id": "01EVT...",
  "status": "confirmed",
  "payment_status": "not_required",
  "reservation_date": "2026-07-20",
  "start_time": "14:00",
  "end_time": "15:00",
  "number_of_guests": 1,
  "created_at": "2026-07-14T02:00:00.000Z"
}

主なエラー

400id must be a 26-char ULIDidの形式不正
404reservation not found存在しない (他テナント含む)
POST/reservations

予約を作成します。枠の空きは原子的に確保され、満席時は 409 を返します。作成時に reservation.created Webhookが発火します。

スコープ: reservations:writeヘッダ: Idempotency-Key 必須

リクエストボディ (JSON)

eventId必須string予約イベントID (ULID)
slotId必須string予約枠ID (ULID)
friendId必須string友だちID (ULID)
numberOfGuestsinteger人数 (1–100、既定 1)
notestringメモ (最大500文字)
staffIdstring指名スタッフID (ULID)

レスポンス例

{
  "id": "01RESV...",
  "event_id": "01EVT...",
  "event_name": "カット予約",
  "slot_id": "01SLOT...",
  "reservation_date": "2026-07-20",
  "start_time": "14:00",
  "end_time": "15:00",
  "number_of_guests": 1,
  "friend_id": "01ABC...",
  "staff_id": null,
  "note": null
}

成功時は 201 を返します。

主なエラー

400予約は{n}分前までに行ってください受付締切 (minNotice) 超過
404event/slot/friend/staff not found対象が存在しない
409slot_full満席 (または直前に枠が変更された)
409duplicate_reservation同じ友だちの二重予約
GET/reservation_events

予約イベント (メニュー) の一覧を取得します。active のもののみ返します。

スコープ: reservations:read

レスポンス例

{
  "data": [
    {
      "id": "01EVT...",
      "name": "カット予約",
      "description": "所要60分",
      "duration": 60,
      "price": 5500,
      "maxCapacity": 1,
      "minNotice": 60,
      "maxAdvance": 30,
      "color": "#06C755",
      "status": "active"
    }
  ]
}
GET/reservation_slots

予約枠を取得します。既定では空きのある枠のみ返します (最大500件)。

スコープ: reservations:read

クエリパラメータ

eventId必須string予約イベントID (ULID)
fromstring開始日 YYYY-MM-DD (既定 今日)
tostring終了日 YYYY-MM-DD (既定 from+30日)
availableOnlystring"false" で満席の枠も含める (既定 true)

レスポンス例

{
  "data": [
    {
      "id": "01SLOT...",
      "eventId": "01EVT...",
      "date": "2026-07-20",
      "startTime": "14:00",
      "endTime": "15:00",
      "maxCapacity": 1,
      "bookedCount": 0
    }
  ],
  "range": { "from": "2026-07-14", "to": "2026-08-13" },
  "eventMaxCapacity": 1
}

主なエラー

400eventId query param is requiredeventId 欠如・形式不正
404event not foundイベントが存在しない

外部ID (External IDs)

外部システム (Shopify・CRM等) の顧客IDとLokuの友だちを紐づけるIDマッピングです。1つの友だちは1つのnamespaceにつき1つの外部IDを持てます。

POST/external-ids

外部IDを友だちに紐づけます。

スコープ: friends:write

リクエストボディ (JSON)

friendId必須string友だちID (ULID)
namespace必須string外部システムの識別子。英小文字・数字・_:- (最大64文字、例: shopify, shopify:store123)
externalId必須string外部システム側のID (1–128文字)

レスポンス例

{
  "data": {
    "id": "01XID...",
    "friendId": "01ABC...",
    "namespace": "shopify",
    "externalId": "cus_12345",
    "source": "api",
    "createdAt": "2026-07-14T02:00:00.000Z",
    "updatedAt": "2026-07-14T02:00:00.000Z"
  }
}

成功時は 201 を返します。

主なエラー

409external_id_in_use同じ namespace + externalId が別の友だちに紐づけ済み
409friend_already_has_namespaceこの友だちが同じ namespace で別の外部IDを保持 (付け替えは /external-ids/replace)
POST/external-ids/replace

外部IDを付け替えます (upsert)。同じ値なら何もしません。

スコープ: friends:write

リクエストボディ (JSON)

friendId必須string友だちID (ULID)
namespace必須string同上
externalId必須string同上

レスポンス例

{ "data": { ... }, "changed": "replaced" }

changed は inserted (201) / replaced (200) / noop (200) のいずれか。

主なエラー

409external_id_owned_by_other_friend別の友だちが同じ外部IDを保持
DELETE/external-ids/{id}

外部IDの紐づけを削除します。

スコープ: friends:write

レスポンス例

{ "ok": true, "id": "01XID..." }

主なエラー

404external-id not found存在しない (他テナント含む)

Webhook購読 (Webhook Endpoints)

Lokuで発生したイベントを外部URLへ配信する購読を管理します。Zapier等の自動化ハブがプログラムから購読・解除するための経路です。レスポンスは snake_case です。

GET/webhook_endpoints

購読の一覧を取得します。署名secretは接頭辞のみ返します。

スコープ: webhooks:read

レスポンス例

{
  "object": "list",
  "data": [
    {
      "id": "01WHEP...",
      "object": "webhook_endpoint",
      "url": "https://hooks.example.com/loku",
      "description": null,
      "events": ["friend.followed", "reservation.created"],
      "status": "active",
      "api_version": "2026-05-23",
      "signing_secret_prefix": "whsec_0123456789",
      "consecutive_failure_count": 0,
      "last_success_at": "2026-07-14T02:00:00.000Z",
      "last_failure_at": null,
      "created_at": "2026-07-14T00:00:00.000Z",
      "updated_at": "2026-07-14T02:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
POST/webhook_endpoints

購読を作成します。署名secret (whsec_...) はこのレスポンスでのみ返され、再表示できません。

スコープ: webhooks:write

リクエストボディ (JSON)

url必須string配信先URL (https、最大2,000文字。プライベートIP等は拒否)
events必須array購読するイベント種別の配列 (1–50件。下記「イベント種別」参照)
descriptionstringメモ (最大500文字)

レスポンス例

{
  "id": "01WHEP...",
  "object": "webhook_endpoint",
  "url": "https://hooks.example.com/loku",
  "events": ["friend.followed"],
  "status": "active",
  "api_version": "2026-05-23",
  "signing_secret_prefix": "whsec_0123456789",
  "signing_secret": "whsec_..." ,
  "created_at": "2026-07-14T02:00:00.000Z"
}

成功時は 201 を返します。signing_secret は必ず保存してください。

主なエラー

400invalid_urlURL がSSRF検証を通らない
403plan_limitプラン上限 (Pro=10、Suite=50。Starter以下は作成不可)
DELETE/webhook_endpoints/{id}

購読を解除します。

スコープ: webhooks:write

レスポンス例

{ "id": "01WHEP...", "object": "webhook_endpoint", "deleted": true }

主なエラー

404webhook_endpoint not found存在しない (他テナント含む)

Webhookイベント種別

POST /webhook_endpoints の events に指定できる値です。

friend.followed友だち追加された
friend.unfollowed友だち解除 (ブロック) された
reservation.created予約が作成された
reservation.cancelled予約がキャンセルされた
form.submittedフォームが回答された
message.received友だちからメッセージを受信した (高頻度)
member.registered会員登録された
member.tier_changed会員ランクが変わった
member.points_addedポイントが付与された
member.visited来店が記録された
payment.succeeded決済が完了した
payment.refunded返金された
payment.failed決済に失敗した
test.pingテスト送信 (ダッシュボードから)

Webhook配信と署名

イベントは以下のJSONで配信されます。配信はat-least-once (最大7回の指数バックオフで再試行) のため、 受信側は id で重複排除してください。連続50回失敗した購読は自動で無効化されます。

{
  "id": "evt_01JCF...",
  "type": "friend.followed",
  "api_version": "2026-05-23",
  "created": 1748131200,
  "livemode": true,
  "data": { /* イベント種別ごとのペイロード */ }
}

すべての配信はHMAC-SHA256で署名されます。2方式を併記するため、どちらでも検証できます:

Loku-Signaturet=<unix>,v1=<hex> — 署名対象は `${timestamp}.${body}` (Stripe互換)
webhook-signatureStandard Webhooks 互換 (webhook-id / webhook-timestamp と併用)。既製SDKで検証できます

タイムスタンプが5分以上ずれた配信は拒否してください (リプレイ攻撃防止)。署名secretのローテーション中は旧secretも24時間有効です。