サクなお

連携の説明

このページでは、お店の今日の営業状態とお店情報を読み出す方法と、ホームページの修正依頼を送る方法を説明します。鍵はお店が発行し、お店が選んだ範囲の情報だけを返します。

鍵と呼び出し方

鍵は、お店が「連携」の画面で発行し、連携先に渡します。鍵は sn_live_ または sn_test_ で始まります。

すべての呼び出しに Authorization: Bearer <鍵> を付けます。回数は鍵ごとに1分60回までです。超えると 429 と Retry-After を返します。

依頼の送信には Idempotency-Key ヘッダーが必要です。同じキーで送り直すと、同じ応答を返します(24時間)。

お店の今日の状態とお店情報は、そのお店が「連携先に伝える」をオンにしているときだけ返します。オフのときは 403 consent_required です。お店の方のお名前・電話番号・メールアドレス・LINEのアカウントは、どの応答にも含まれません。

時刻は +09:00 付きの ISO 8601、日付は YYYY-MM-DD です。一覧は limit(1〜100、既定50)と cursor で続きを取ります。

OpenAPI の定義(/api/partner/v1/openapi.json)

エンドポイント

メソッドパススコープ内容
GET/api/partner/v1/pingどれでも鍵の確認
GET/api/partner/v1/openapi.json不要OpenAPI 3.1 の定義(鍵は不要)
GET/api/partner/v1/shopsshop_status:read / shop_facts:read / tickets:read / tickets:writeお店の一覧と、連携先に伝える同意の有無
GET/api/partner/v1/shops/{id}/statusshop_status:readお店の今日の状態:営業日か・今営業中か・今日の営業時間・臨時休業・お知らせ
GET/api/partner/v1/shops/{id}/factsshop_facts:readお店情報の正本(今有効なもの/as_of の日のもの/include_history=true で履歴)
POST/api/partner/v1/ticketstickets:write修正依頼の送信。お店の承認の流れは同じで、省略できません
GET/api/partner/v1/ticketstickets:read同じ鍵で送った依頼の一覧
GET/api/partner/v1/tickets/{id}tickets:read同じ鍵で送った依頼の状態

イベント(Webhook)

イベントいつ条件
shop.info_changedお店情報の正本が変わったときお店が「連携先に伝える」をオンにしているときだけ
ticket.published依頼が公開されたときなし(依頼の本文・見本のURLは含みません)
ticket.needs_approval見本をお店に送り、承認待ちになったときなし(依頼の本文・見本のURLは含みません)

本文は {"id","type","created_at","org_id","data"} の形です。同じ出来事には同じ id を付けます。

順番は保証しません。created_at で判断してください。

署名の確かめ方

ヘッダー X-SBGG-Signature: t=<UNIX秒>,v1=<署名> が付きます。署名は、宛先を登録したときに表示された秘密で、t と本文を「.」でつないだ文字列の HMAC-SHA256(16進)です。

t が今から300秒以上ずれていたら捨ててください。宛先は https だけです。

// Node.js
import crypto from 'node:crypto';

function verify(secret, rawBody, header) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const t = Number(parts.t);
  if (Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

curl の例

お店の今日の状態を取る

curl -s https://sakunao.jp/api/partner/v1/shops/{shop_id}/status \
  -H "Authorization: Bearer sn_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

修正依頼を送る

curl -s -X POST https://sakunao.jp/api/partner/v1/tickets \
  -H "Authorization: Bearer sn_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c1e2b4a-9f10-4d2e-8a3b-5c6d7e8f9012" \
  -d '{"shop_id":"{shop_id}","request_text":"営業時間を10時からに変えて","external_ref":"WEB-889"}'

修正依頼は、お店がLINEで見本を確認して「公開する」を押すまで公開されません。

エラー

エラーは {"error":{"code","message"}} の形です。401 unauthorized、403 forbidden/consent_required/account_inactive、404 not_found、409 line_not_linked/quota_exceeded/conflict(同じ Idempotency-Key で違う内容)、422 validation_error、429 rate_limited。