1.概要
JSON を返す REST API です。すべてのエンドポイントは /api/v1 の下にあります。
| 項目 | 内容 |
|---|---|
| ベースURL | https://(このサイトのドメイン)/api/v1 |
| 形式 | リクエスト・応答ともに JSON(UTF-8) |
| 認証 | APIキー(Authorization: Bearer) |
| バージョン | v1.0.0(パスの /v1 が変わらない限り、後方互換を壊す変更はしません) |
| 対象範囲 | APIキーを発行した店舗のデータのみ |
できること・できないこと
商品の登録・更新・削除、予約の参照とステータス変更、受取枠の参照ができます。予約の新規作成はAPIでは行えません(在庫と枠の整合を守るため、 お客様向けの予約ページからのみ受け付けます)。2.認証
- 1管理画面の「データ連携 → API連携」で APIキーを発行します。 権限は
read(参照のみ)とwrite(参照と更新)から選びます。 - 2発行直後に表示されるキーを控えます。表示されるのはこの一度きりで、あとから確認する方法はありません。
- 3リクエストの
Authorizationヘッダーに付けて送ります。
Authorization: Bearer rg_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
キーは店舗に紐づいています。1本のキーから見えるのは、その発行元の店舗のデータだけです。 複数店舗を運営している場合は、店舗ごとにキーを発行してください。
キーの取り扱い
キーはパスワードと同じです。ブラウザで動くコードや公開リポジトリには置かないでください。 漏れた可能性があるときは管理画面から「無効化」し、新しいキーを発行してください。 無効化したキーは即座に401 を返すようになります。3.共通の約束ごと
日付と時刻
pickupDate/pickupTimeと、クエリのdate/from/toはすべて日本時間(JST)の文字列です(YYYY-MM-DD、HH:mm)createdAt/updatedAt/pickupAtは ISO 8601 の UTC(2026-08-27T00:00:00.000Z)です
金額
すべて税込の整数(円)です。unitPrice にはオプションの追加料金が 含まれます(amount = unitPrice × qty)。
一覧のページング
一覧系は limit(既定50・最大200)と offset を受け取り、pagination を添えて返します。
{
"data": [ ... ],
"pagination": { "total": 128, "limit": 50, "offset": 0, "hasMore": true }
}部分更新
PATCH はボディに書いた項目だけを変更します。 省略した項目は現在の値のままです。
レート制限
APIキーごとの回数制限は設けていません。ただしDBへの負荷を避けるため、一覧の取得は limit(最大200)で区切り、定期取得は必要な範囲だけを指定してください。
予約フォーム側の制限
お客様向けの予約ページには連投の抑止があります(同一IP・同一電話番号で短時間に集中した場合)。APIからの参照・更新はこの制限の対象外です。
互換性
既存フィールドの削除や意味の変更は行いません。フィールドの追加はあり得るので、未知のキーを無視できる作りにしておいてください。
4.エラー
失敗したときは、HTTPステータスと合わせて次の形の JSON を返します。
{
"error": {
"code": "invalid_request",
"message": "日付は YYYY-MM-DD 形式で指定してください。",
"details": [{ "field": "date", "message": "..." }]
}
}| code | HTTP | 起きるとき |
|---|---|---|
unauthorized | 401 | APIキーが未指定・不正・無効化済み。 |
forbidden | 403 | read キーで更新系を呼んだ。 |
invalid_request | 400 | パラメータやリクエストボディが不正。 |
not_found | 404 | 指定したIDのデータが無い。 |
conflict | 409 | SKUの重複、在庫不足などで処理できない。 |
server_error | 500 | サーバー側の想定外のエラー。 |
message はそのまま画面に出せる日本語です。 処理の分岐には code を使ってください。
5.エンドポイント
/api/v1/shopread でも可店舗情報を取得する
APIキーに紐づく店舗の基本情報・受付設定・営業時間・臨時休業日を返します。
応答の例
{
"id": "clx1shop00001",
"slug": "garoop-omiyage",
"name": "ガループ物産 京都駅前店",
"kind": "souvenir",
"accepting": true,
"slotIntervalMin": 60,
"leadTimeMin": 720,
"maxDaysAhead": 30,
"slotCapacity": 40,
"maxItemsPerOrder": 30,
"businessHours": [
{ "weekday": 0, "openTime": "09:00", "closeTime": "20:00", "closed": false }
],
"closedDates": [{ "date": "2027-01-01", "reason": "元日" }]
}/api/v1/availabilityread でも可受取枠の空き状況を取得する
公開ページと同じ計算(営業時間・定休日・臨時休業日・リードタイム・枠あたりの上限)で、受取可能な日付と時間枠を返します。remaining が null のときは枠の上限を設けていません。
パラメータ
| from | string | この日以降に絞る(JST・YYYY-MM-DD)。 |
| to | string | この日以前に絞る(JST・YYYY-MM-DD)。 |
| openOnly | boolean | true なら、選べる枠が1つ以上ある日だけを返します。指定できる値: true / false |
応答の例
{
"accepting": true,
"slotIntervalMin": 60,
"leadTimeMin": 720,
"slotCapacity": 40,
"data": [
{
"date": "2026-09-01",
"weekday": 2,
"closed": false,
"closedReason": null,
"hasOpenSlot": true,
"slots": [
{ "time": "09:00", "remaining": 40, "disabled": false },
{ "time": "10:00", "remaining": 38, "disabled": false }
]
}
]
}/api/v1/categoriesread でも可商品カテゴリの一覧
並び順の昇順で返します。
応答の例
{
"data": [
{ "id": "clx1category001", "name": "銘菓", "sortOrder": 0,
"createdAt": "2026-08-26T00:00:00.000Z", "updatedAt": "2026-08-26T00:00:00.000Z" }
]
}/api/v1/optionsread でも可オプション(ラッピング等)の一覧
オプショングループと、その選択肢を返します。selectType は single(1つだけ)または multi(いくつでも)です。
応答の例
{
"data": [
{
"id": "clx1group0001",
"name": "ラッピング",
"description": "贈りもの用の包装をお選びいただけます。",
"selectType": "single",
"required": true,
"sortOrder": 0,
"choices": [
{ "id": "clx1choice001", "name": "掛け紙(無料)", "priceDelta": 0, "sortOrder": 1, "available": true },
{ "id": "clx1choice002", "name": "化粧箱入り", "priceDelta": 330, "sortOrder": 2, "available": true }
]
}
]
}/api/v1/productsread でも可商品の一覧
絞り込みとページングに対応しています。
パラメータ
| q | string | 商品名・SKU の部分一致(大文字小文字を区別しません)。 |
| categoryId | string | カテゴリIDで絞り込みます。 |
| available | boolean | 公開中(true)/非公開(false)で絞り込みます。指定できる値: true / false |
| limit | integer | 1回に返す件数(1〜200)。既定値: 50 |
| offset | integer | 読み飛ばす件数。ページングに使います。既定値: 0 |
応答の例
{
"data": [{
"id": "clx1product0001",
"sku": "OMI-001",
"name": "抹茶生八つ橋 15個入",
"description": "宇治抹茶をたっぷり使った定番の生八つ橋。",
"price": 980,
"imageUrl": "https://example.com/yatsuhashi.jpg",
"categoryId": "clx1category001",
"available": true,
"sortOrder": 0,
"maxPerOrder": 0,
"stock": null,
"optionGroupIds": ["clx1group0001", "clx1group0002"],
"createdAt": "2026-08-26T00:00:00.000Z",
"updatedAt": "2026-08-26T00:00:00.000Z"
}],
"pagination": { "total": 7, "limit": 50, "offset": 0, "hasMore": false }
}/api/v1/productswrite キーが必要商品を登録する
sku を指定した場合、店舗内で重複していると 409 を返します。categoryId と optionGroupIds は同じ店舗のものだけ指定できます。
リクエストボディ(JSON)
| name必須 | string | 商品名(120文字まで)。 |
| price必須 | integer | 税込単価(円)。 |
| sku | string | null | 商品コード。店舗内で一意。 |
| description | string | null | 説明(500文字まで)。 |
| imageUrl | string | null | 画像URL(http/https)。 |
| categoryId | string | null | カテゴリID。 |
| available | boolean | 公開するか。既定 true。 |
| sortOrder | integer | 並び順。小さいほど先。既定 0。 |
| maxPerOrder | integer | 1予約あたりの上限。0 で無制限。 |
| stock | integer | null | 在庫数。null で在庫管理しない。 |
| optionGroupIds | string[] | この商品で使うオプショングループのID。 |
応答の例
{
"id": "clx1product0001",
"sku": "OMI-001",
"name": "抹茶生八つ橋 15個入",
"description": "宇治抹茶をたっぷり使った定番の生八つ橋。",
"price": 980,
"imageUrl": "https://example.com/yatsuhashi.jpg",
"categoryId": "clx1category001",
"available": true,
"sortOrder": 0,
"maxPerOrder": 0,
"stock": null,
"optionGroupIds": ["clx1group0001", "clx1group0002"],
"createdAt": "2026-08-26T00:00:00.000Z",
"updatedAt": "2026-08-26T00:00:00.000Z"
}/api/v1/products/{id}read でも可商品を1件取得する
見つからない場合は 404 を返します。
パラメータ
| id必須 | string | 商品ID。 |
応答の例
{
"id": "clx1product0001",
"sku": "OMI-001",
"name": "抹茶生八つ橋 15個入",
"description": "宇治抹茶をたっぷり使った定番の生八つ橋。",
"price": 980,
"imageUrl": "https://example.com/yatsuhashi.jpg",
"categoryId": "clx1category001",
"available": true,
"sortOrder": 0,
"maxPerOrder": 0,
"stock": null,
"optionGroupIds": ["clx1group0001", "clx1group0002"],
"createdAt": "2026-08-26T00:00:00.000Z",
"updatedAt": "2026-08-26T00:00:00.000Z"
}/api/v1/products/{id}write キーが必要商品を更新する
指定した項目だけを変更します。optionGroupIds を指定した場合はその内容で置き換え、指定しなければ現状のままです。
パラメータ
| id必須 | string | 商品ID。 |
リクエストボディ(JSON)
| name | string | 商品名。 |
| price | integer | 税込単価(円)。 |
| stock | integer | null | 在庫数。 |
| available | boolean | 公開するか。 |
| … | - | そのほか、登録時と同じ項目を指定できます。 |
応答の例
{
"id": "clx1product0001",
"sku": "OMI-001",
"name": "抹茶生八つ橋 15個入",
"description": "宇治抹茶をたっぷり使った定番の生八つ橋。",
"price": 980,
"imageUrl": "https://example.com/yatsuhashi.jpg",
"categoryId": "clx1category001",
"available": true,
"sortOrder": 0,
"maxPerOrder": 0,
"stock": null,
"optionGroupIds": ["clx1group0001", "clx1group0002"],
"createdAt": "2026-08-26T00:00:00.000Z",
"updatedAt": "2026-08-26T00:00:00.000Z"
}/api/v1/products/{id}write キーが必要商品を削除する
過去の予約明細は商品名を控えているため、削除しても受注履歴は残ります。
パラメータ
| id必須 | string | 商品ID。 |
応答の例
{ "deleted": true, "id": "clx1product0001" }/api/v1/reservationsread でも可予約の一覧
受取日時の早い順に返します。status を省略すると、キャンセル以外(active)だけが対象です。
パラメータ
| date | string | 受取日ちょうど1日ぶん(JST・YYYY-MM-DD)。from / to より優先されます。 |
| from | string | 受取日の開始(JST・両端を含む)。 |
| to | string | 受取日の終了(JST・両端を含む)。 |
| status | string | ステータス。pending(受付済) / confirmed(確定) / ready(準備完了) / completed(受渡済) / canceled(キャンセル)。active(キャンセル以外・既定)/ all も指定できます。指定できる値: pending / confirmed / ready / completed / canceled / active / all |
| code | string | 受付番号での完全一致。 |
| limit | integer | 1回に返す件数(1〜200)。既定値: 50 |
| offset | integer | 読み飛ばす件数。ページングに使います。既定値: 0 |
応答の例
{
"data": [{
"id": "clx1reservation01",
"code": "387169",
"status": "pending",
"customerName": "山田 太郎",
"customerPhone": "090-1234-5678",
"customerEmail": null,
"pickupAt": "2026-08-27T00:00:00.000Z",
"pickupDate": "2026-08-27",
"pickupTime": "09:00",
"total": 4300,
"totalQty": 3,
"note": "のし名入れ: 山下",
"items": [
{
"id": "clx1item0001",
"productId": "clx1product0001",
"label": "抹茶生八つ橋 15個入",
"options": "ラッピング: ギフト包装(リボン付き)(+¥550) / のし: 御中元",
"unitPrice": 1530,
"qty": 2,
"amount": 3060
}
],
"createdAt": "2026-08-26T01:23:45.000Z",
"updatedAt": "2026-08-26T01:23:45.000Z"
}],
"pagination": { "total": 1, "limit": 50, "offset": 0, "hasMore": false }
}/api/v1/reservations/{idOrCode}read でも可予約を1件取得する
予約ID・受付番号(6桁)のどちらでも引けます。店頭のPOSからは受付番号で照会できます。
パラメータ
| idOrCode必須 | string | 予約ID または 受付番号。 |
応答の例
{
"id": "clx1reservation01",
"code": "387169",
"status": "pending",
"customerName": "山田 太郎",
"customerPhone": "090-1234-5678",
"customerEmail": null,
"pickupAt": "2026-08-27T00:00:00.000Z",
"pickupDate": "2026-08-27",
"pickupTime": "09:00",
"total": 4300,
"totalQty": 3,
"note": "のし名入れ: 山下",
"items": [
{
"id": "clx1item0001",
"productId": "clx1product0001",
"label": "抹茶生八つ橋 15個入",
"options": "ラッピング: ギフト包装(リボン付き)(+¥550) / のし: 御中元",
"unitPrice": 1530,
"qty": 2,
"amount": 3060
}
],
"createdAt": "2026-08-26T01:23:45.000Z",
"updatedAt": "2026-08-26T01:23:45.000Z"
}/api/v1/reservations/{idOrCode}write キーが必要予約のステータスを変更する
管理画面と同じ処理を通ります。canceled にすると在庫管理中の商品の在庫が戻り、canceled から戻すと再度引き当てます。在庫が足りず引き当て直せない場合は 409 を返します。
パラメータ
| idOrCode必須 | string | 予約ID または 受付番号。 |
リクエストボディ(JSON)
| status必須 | string | pending(受付済) / confirmed(確定) / ready(準備完了) / completed(受渡済) / canceled(キャンセル) のいずれか。 |
応答の例
{
"id": "clx1reservation01",
"code": "387169",
"status": "pending",
"customerName": "山田 太郎",
"customerPhone": "090-1234-5678",
"customerEmail": null,
"pickupAt": "2026-08-27T00:00:00.000Z",
"pickupDate": "2026-08-27",
"pickupTime": "09:00",
"total": 4300,
"totalQty": 3,
"note": "のし名入れ: 山下",
"items": [
{
"id": "clx1item0001",
"productId": "clx1product0001",
"label": "抹茶生八つ橋 15個入",
"options": "ラッピング: ギフト包装(リボン付き)(+¥550) / のし: 御中元",
"unitPrice": 1530,
"qty": 2,
"amount": 3060
}
],
"createdAt": "2026-08-26T01:23:45.000Z",
"updatedAt": "2026-08-26T01:23:45.000Z"
}6.よくある使い方
当日の受取予定を取り込む
curl -H "Authorization: Bearer $RESERVEG_KEY" \ "https://example.com/api/v1/reservations?date=2026-09-01"
status を省略しているので、キャンセル以外の予約が受取時刻の早い順に返ります。 件数が50件を超える場合は pagination.hasMore を見て offset を進めてください。
店頭で受け渡したことを記録する
curl -X PATCH -H "Authorization: Bearer $RESERVEG_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"completed"}' \
"https://example.com/api/v1/reservations/387169"受付番号でそのまま指定できるので、店頭で読み上げてもらった番号をPOSに入力するだけで済みます。
在庫を基幹システムから同期する
# 1. SKU で商品を探す
curl -H "Authorization: Bearer $RESERVEG_KEY" \
"https://example.com/api/v1/products?q=OMI-001"
# 2. 見つかったIDの在庫を更新する
curl -X PATCH -H "Authorization: Bearer $RESERVEG_KEY" \
-H "Content-Type: application/json" \
-d '{"stock": 24}' \
"https://example.com/api/v1/products/clx1product0001"空いている枠を自社サイトに表示する
curl -H "Authorization: Bearer $RESERVEG_KEY" \ "https://example.com/api/v1/availability?openOnly=true&to=2026-09-07"
予約ページと同じ計算結果が返るので、表示がずれることはありません。 実際の予約は予約ページ(/s/店舗のURL)へ誘導してください。
7.機械可読の仕様(OpenAPI)
OpenAPI 3.1 の定義を /api/v1/openapi.json で配信しています(認証不要)。Swagger UI・Postman・各言語のコード生成に そのまま読み込めます。
# Postman: File → Import → Link に上記URLを貼る # openapi-generator でクライアントを作る例 npx @openapitools/openapi-generator-cli generate \ -i https://example.com/api/v1/openapi.json \ -g typescript-fetch -o ./reserveg-client
この仕様書と openapi.json は同じ定義(src/lib/api/spec.ts)から 生成しているため、内容が食い違うことはありません。
