API ドキュメント
概要
オープン API は 2 つの仕組みを提供します:①プル——第三者が HTTP API を呼び出し、条件を指定して予約データを取得する;②プッシュ——新しい予約が発生した際、システムが設定済みの通知先へ appointment.created イベントを送信する。両者は同一の HMAC-SHA256 署名を共有します。認証情報は 2 つに分かれ、API Key は身元を識別しリクエストヘッダーに平文で送られ、API Secret は署名の計算に使われリクエスト本文には一切現れません。シークレットの再発行では API Secret のみが変わり、API Key は変わりません。
プル API
GET https://phone-api.bookmi.ai/api/open/v1/appointments
リクエストヘッダー
| 名称 | 説明 |
|---|---|
| X-Api-Key | 身元識別用の API Key(ak_ で始まる) |
| X-Timestamp | Unix 秒のタイムスタンプ(文字列)。サーバー時刻の ±300 秒以内であること |
| X-Signature | 本リクエストの HMAC-SHA256 署名(小文字 16 進数) |
署名アルゴリズム
署名対象文字列は 4 行を改行で連結して作ります:1 行目はタイムスタンプ、2 行目は HTTP メソッド(GET)、3 行目はリクエストパス /api/open/v1/appointments、4 行目は query string。query string は実際に送信したものと 1 文字単位で完全一致させ、並べ替えや再エンコードをしないこと(パラメータが無ければ空文字列)。この文字列を API Secret を鍵として HMAC-SHA256 で計算し、小文字 16 進数を X-Signature とします。タイムスタンプは Unix 秒でサーバー時刻の ±300 秒以内でなければ期限切れと見なされます。
クエリパラメータ
| 名称 | 説明 |
|---|---|
| updated_since | この時刻以降に更新された予約のみ返す(ISO 8601) |
| scheduled_from | 予約時刻の下限(ISO 8601) |
| scheduled_to | 予約時刻の上限(ISO 8601) |
| status | ステータスで絞り込み:pending / confirmed / cancelled |
| page | ページ番号、1 から(既定 1) |
| page_size | 1 ページの件数、1-200(既定 50) |
レスポンス例
{
"code": 0,
"message": "ok",
"data": {
"total": 128,
"items": [
{
"id": 1024,
"scheduled_at": "2026-07-20T10:00:00+09:00",
"party_size": 2,
"contact_name": "山田太郎",
"contact_phone": "+819012345678",
"subject": "カット予約",
"note": null,
"status": "confirmed",
"outside_slot": false,
"item_name": "カット",
"item_external_id": "svc_001",
"created_at": "2026-07-16T12:34:56+09:00",
"updated_at": "2026-07-16T12:34:56+09:00"
}
]
}
}フィールド説明
| フィールド | 説明 |
|---|---|
| id | 予約の主キー |
| scheduled_at | 予約時刻(null 可) |
| party_size | 人数 / 数量(null 可) |
| contact_name | 連絡先氏名(null 可) |
| contact_phone | 連絡先電話番号(null 可) |
| subject | 予約の用件 |
| note | 備考(null 可) |
| status | ステータス:pending / confirmed / cancelled |
| outside_slot | 予約不可の時間帯(定休 / 時間外 / 満員)に入るか |
| item_name | 商品名のスナップショット(null 可) |
| item_external_id | 第三者の商品 ID スナップショット。店舗の商品に完全一致した場合のみ値が入る(null 可) |
| created_at | 作成日時 |
| updated_at | 更新日時 |
プッシュ通知
通知先を設定すると、新しい予約が作成されるたびに(AI 抽出または手動登録)、システムがその通知先へ POST リクエストを 1 回送信します。本文は下記の JSON です。
プッシュ本文の例
{
"event": "appointment.created",
"delivery_id": 8801,
"timestamp": 1752633600,
"data": {
"id": 1024,
"scheduled_at": "2026-07-20T10:00:00+09:00",
"party_size": 2,
"contact_name": "山田太郎",
"contact_phone": "+819012345678",
"subject": "カット予約",
"note": null,
"status": "pending",
"outside_slot": false,
"item_name": "カット",
"item_external_id": "svc_001",
"created_at": "2026-07-16T12:34:56+09:00",
"updated_at": "2026-07-16T12:34:56+09:00"
}
}プッシュ署名
プッシュのリクエストヘッダーには X-Timestamp と X-Signature が付きます:署名対象は「タイムスタンプ + 半角ピリオド + 本文の生バイト」で、API Secret を鍵として HMAC-SHA256 で計算します。受信側は署名を再計算して照合し、一致した場合のみ処理してください。2xx を返せば配信成功と見なします。
リトライと冪等性
配信失敗(2xx 以外またはタイムアウト)は自動でリトライされ、間隔は順に 1 分・5 分・30 分・2 時間・6 時間、初回を含め計 6 回試行し、すべて失敗すると終了状態となり以後配信しません。同一予約の複数回の配信は同じ delivery_id を持つため、これで重複排除して冪等性を確保してください。テスト送信を初めて設定する際は、event が webhook.test の検査用イベント(data は空オブジェクト)を先に 1 通送ります。
エラーコード
業務エラーは HTTP ステータスに加え、レスポンス本文の code フィールドで下記の業務コードを返します。
| 業務コード | HTTP | 意味 |
|---|---|---|
| 1801 | 403 | オープン API 機能が未開放 |
| 1802 | 401 | API Key が無効 |
| 1803 | 401 | 署名が無効、またはタイムスタンプ期限切れ |
| 1804 | 400 | 通知先が不正 |
| 1805 | 400 | 先に認証情報を生成し通知先を設定してください |
コード例
プル(curl)
# 拉取预约(签名 = HMAC-SHA256(secret, ts + "\n" + "GET" + "\n" + path + "\n" + query))
TS=$(date +%s)
QUERY="page=1&page_size=50"
SIG=$(printf '%s\nGET\n/api/open/v1/appointments\n%s' "$TS" "$QUERY" \
| openssl dgst -sha256 -hmac "$API_SECRET" -hex | awk '{print $NF}')
curl "https://phone-api.bookmi.ai/api/open/v1/appointments?$QUERY" \
-H "X-Api-Key: ak_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -H "X-Timestamp: $TS" -H "X-Signature: $SIG"プッシュ検証(Python)
# 推送验签(收到 POST 时)
import hashlib, hmac
def verify(secret: str, timestamp: str, body: bytes, signature: str) -> bool:
expected = hmac.new(secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)