Webhook について
Webhook(ウェブフック)とはBカートで発生した各種イベントを利用者の用意したシステムへ通知を行う仕組みです。
エンドポイントを登録すると、指定したイベント(注文登録や変更時など)が発生した場合にエンドポイントURLにデータがPOSTされることになります。
ご利用いただくにはエンドポイントでデータを受信し、設定したSecretの正当性を確認するシステムをご用意いただく必要があるため開発者様向けの内容となっております。
※ webhookはリアルタイムでの連携が実現可能となりますが、配信が必ず保証されているわけではございません。注意事項の詳細はWebhookの制約についてをご確認ください。
Webhookの制約について
Bカートのwebhookは仕様を変更する場合がございますのでご了承ください。
またご利用いただく上でいくつか注意点がございますので、ご利用いただく前に必ずご確認をお願いします。
配信に関して
・Webhookの配信は常に保証されているわけではありません。そのため整合性を担保する必要がある場合は、API等で定期的にデータを確認する必要があります。
・Webhookの配信は同一イベントが複数回送信される可能性がございます。そのため冪等性を担保する場合は、Payloadの「event_id」という一意の項目で判別する必要があります。
エラーに関して
以下のようなエラーが発生した場合、Webhookでのトラブルシューティングに必要な情報を確認することができません。
・Webhook に設定したエンドポイントURLの誤り
・エンドポイントURLのDNSによる名前解決のエラー
・Webhookを受信する、ご用意いただいたシステムのエラーによる通知失敗
・ご用意いただいたシステムのダウン
・ご用意いただいたシステムのhttpsポートの異常
・ご用意いただいたシステムの側の通信遮断による失敗
Webhookの設定
各種設定 > 外部連携 > Webhook にて登録・編集が可能です。
Webhookの名称
目的に応じた管理しやすい名称を自由に登録できます。
Webhook URL
BカートWebhookを受信するお客様がご用意されたURIを記載してください。
(受信するURIはSSL証明書の付与されたhttps://で始まる必要があります。)
イベント
設定できるイベントは下記になります。受信したいイベント名を選択してください。
イベント名 | Payloadのevent_type | 説明 |
---|---|---|
注文登録 | order.created | ユーザーの注文時、管理画面から新規受注作成や複製 |
注文変更 | order.updated | 管理画面から受注情報(受注商品や出荷含む)の変更、対応状況や発送状況変更 ※ 外部決済のステータスの変更は通知しない。 |
会員登録 | customer.created | ユーザーの会員登録、承認グループ管理者の会員登録、管理画面からの新規会員登録や会員承認 |
会員変更 | customer.updated | ユーザーがMYページから会員情報変更、承認グループ管理者の会員情報変更、Paidの申請や申請状況変更、管理画面からの会員情報変更 |
別配送先登録 | other_address.created | |
別配送先変更 | other_address.updated |
※ CSVでのインポート時、BカートAPIからの操作の場合はWebhookの通知はされません。
シークレット
署名の正当性チェックを行うために必要なシークレットを36文字以上の不規則な半角文字列を登録してください。
※ 正当性チェックを行わなくてもWebhookは受信出来ますが、他の悪意ある攻撃も受け付ける危険性があるので、正当性チェックを行いことを強くおすすめします。
状態
『有効』か『無効』の切り替えが可能です。
データについて
headerの情報
フィールド名 | 値の説明 |
---|---|
Bcart-Signature | date=日時文字列,v1=Signature文字列 |
Content-Type | application/json |
サンプル
Bcart-Signature:date=20200225T080029Z,v1=9500c80e7b9b272f9b0cfb9791cf315d704a72509e2201021ba4647235d1170b Content-Type:application/json
Payload
共通の項目
フィールド名 | 説明 | サンプル |
---|---|---|
event_id | 発生したイベントのユニークなID | 749a4f9b-d366-4bfd-82d2-37db8785cxxx |
event_type | 発生したイベントのタイプ | customer.created |
created_at | 発生時刻 | 2020-02-25T08:29:38.944105 |
retry_count | 受信されずにリトライした回数 | 0 |
subscription_id | Webhook設定のID | 9d0841ab-4ef6-4662-868d-8b2e48668xxx |
idempotency_key | BカートのWebhookでは利用されません | null |
data | 登録・編集されたBカートの情報 |
{ "event_id":"749a4f9b-d366-4bfd-82d2-37db8785cxxx", "event_type":"customer.updated", // イベントのタイプが入ります。 "created_at":"2020-02-25T08:29:38.944105", "retry_count":0, "subscription_id":"9d0841ab-4ef6-4662-868d-8b2e4866808d", "idempotency_key":null, "data":{ "object":{ "id":10135, // 対象のデータが入ります。 "created_at":"2019-11-08 17:37:48", "updated_at":"2020-02-25 17:29:33" }, "previous":null } }
署名の正当性チェック
受信したデータがBカートから正しく発信されたデータであるという正当性を確認するために Bcart-SignatureをHTTPヘッダーとして送信しています。
Bcart-SignatureとBカート管理画面で設定したSecretを使ってデータが改変されていないことを確認してください。
正当性の確認の手順は下記になります。
Bcart-Signatureの内容は下記のような文字列になります。
下記文字列からdateの値とv1の値を取得してください。
date=20200107T062235Z,v1=9500c80e7b9b272f9b0cfb9791cf315d704a72509e2201021ba4647235d1170b
取得したdateの値とWebhookのBodyを.(ドット)で連結してください。
連結した文字列をHMAC(SHA256)と設定したSecretをキーとして使いハッシュ値を計算します。
このハッシュ値とv1の値が同じてあれば正当性がチェックされた状態になります。
PHPでの正当性チェック
<?php define('SECRET', '6jTXomCiE6WAzRvLiCPtUoAiFZArsNWFUhG7'); $headers = getallheaders(); $payload = json_decode(file_get_contents('php://input'), true); $bcart_signature = explode(',', $headers['Bcart-Signature']); $utc_string = substr($bcart_signature[0], 5); $signature = substr($bcart_signature[1], 3); $expected_signature_string = $utc_string.'.'.json_encode($payload); $expected_signature = hash_hmac('sha256', $expected_signature_string, SECRET); if ($expected_signature != $signature) { die('署名が不正です。'); } else { echo "この「{$payload['event_type']}」に使われている署名は正当!"; }
Pythonでの正当性チェック
from flask import Flask, request import json import hmac import hashlib SECRET = '6jTXomCiE6WAzRvLiCPtUoAiFZArsNWFUhG7' app = Flask(__name__) def isSignatureValid(request): if 'Bcart-Signature' not in request.headers: return False bcart_signature_strings = request.headers.get('Bcart-Signature').split(',') payload = request.get_json() utc_string = bcart_signature_strings[0][5:] signature = bcart_signature_strings[1][3:] expected_signature_string = '%s.%s' % (utc_string, json.dumps( payload, separators=(',', ':'))) expected_signature = hmac.new(SECRET.encode(), msg=expected_signature_string.encode(), digestmod=hashlib.sha256).hexdigest() return signature == expected_signature @app.route('/', methods=['POST']) def index(): if (isSignatureValid(request) == False): return '署名が不正です。' req_data = request.get_json() return 'この「%s」に使われている署名は正当!' % (req_data['event_type']) if __name__ == "__main__": app.run(host='0.0.0.0', port=5000, threaded=True, debug=True)
data
共通仕様
データの中身はObjectとPreviousがあり、Objectの中が登録・更新された情報
オブジェクト内の順番は固定されません。
Previousは常にnullでBカートWebhookでは利用されません。
会員情報
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
id | 会員ID | 整数 | 10039 |
ext_id | 貴社独自会員ID | 文字列 | |
agent_id | 代理店ID | 文字列 | |
agent_rate | 代理店レート | 数値 | |
parent_id | 親会員ID | 整数 | |
destination_code | 配送コード | 文字列 | ABC-1234 |
comp_name | 会社名 | 文字列 | 株式会社ダミー商事 |
comp_name_kana | 会社名カナ | 文字列 | ダミーショウジ |
ceo_last_name | 代表者姓 | 文字列 | 山田 |
ceo_first_name | 代表者名 | 文字列 | 太郎 |
ceo_last_name_kana | 代表者姓カナ | 文字列 | ヤマダ |
ceo_first_name_kana | 代表者名カナ | 文字列 | タロウ |
department | 部署 | 文字列 | 営業部 |
tanto_last_name | 担当者姓 | 文字列 | 山本 |
tanto_first_name | 担当者名 | 文字列 | 一郎 |
tanto_last_name_kana | 担当者姓カナ | 文字列 | ヤマモト |
tanto_first_name_kana | 担当者名カナ | 文字列 | イチロウ |
zip | 郵便番号 | 文字列 | 100-0014 |
pref | 都道府県 | 文字列 | 東京都 |
address1 | 市区町村 | 文字列 | 千代田区永田町 |
address2 | 町域・番地 | 文字列 | 一丁目 |
address3 | ビル・建物名 | 文字列 | |
メールアドレス | 文字列 | test@test.test | |
email_cc | メールアドレスCC | 文字列 | cc1@test.test,cc2@test.test |
tel | 電話番号 | 文字列 | 03-0000-0000 |
mobile_phone | 携帯番号 | 文字列 | 090-0000-0000 |
fax | FAX番号 | 文字列 | 03-0000-0000 |
url | URL | 文字列 | https://dai.co.jp |
foundation | 設立年月 | 文字列 | 2000-2 |
sales | 年商 | 整数 | 1000000 |
job | 業態/業種 | 文字列 | 卸売業 |
memo | 管理者用メモ | 文字列 | |
payment | 決済方法 | 文字列 | 銀行振込,代金引換 |
special_shipping_cost | 特別送料 | 数値 | |
mm_flag | メルマガフラグ | 整数 | 1 |
point | ポイント | 整数 | 0 |
price_group_id | 価格グループID | 整数 | 1 |
view_group_id | 表示グループID | 整数 | 1 |
customs | カスタム項目 | 配列 | 会員カスタム項目を参照 |
salesman_id | 営業担当者ID | 文字列 | |
af_id | 参照元ID | 文字列 | |
cutoff_date | 締め日 | 文字列 | |
payment_month | 支払い日(月) | 文字列 | |
payment_date | 支払い日(日) | 文字列 | |
default_other_shipping_id | 基本別配送先ID | 整数 | |
default_payment | 基本支払い方法 | 文字列 | 銀行振込 |
hidden_price | 価格表示設定 | 整数 | 0 |
status | 会員認証 | 文字列 | |
created_at | 登録日 | 日付 | 2020-12-17 16:11:16 |
updated_at | 更新日 | 日付 | 2020-12-17 16:11:16 |
注文情報
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
id | 受注ID | 整数 | 1 |
code | 受注番号 | 整数 | 16075767282 |
affiliate_id | 参照元ID | 文字列 | |
estimate_id | 見積番号 | 文字列 | |
customer_salesman_id | 営業担当者 | 文字列 | |
customer_id | Bカート会員ID | 整数 | 9999 |
customer_parent_id | 親会員ID | 文字列 | BCART-001 |
customer_ext_id | 貴社独自会員ID | 文字列 | BCART-001 |
customer_name | 担当者 | 文字列 | 山田一郎 |
customer_comp_name | 会社名 | 文字列 | Bカートサポートセンター |
customer_department | 部署名 | 文字列 | お客様サポート |
customer_tel | 電話番号 | 文字列 | 075-000-0000 |
customer_mobile_phone | 携帯番号 | 文字列 | |
customer_email | メールアドレス | 文字列 | test@aaaaa.aa |
customer_price_group_id | 価格グループ | 文字列 | 1 |
customer_zip | 郵便番号 | 文字列 | 600-0000 |
customer_pref | 都道府県 | 文字列 | 京都府 |
customer_address1 | 市区町村 | 文字列 | |
customer_address2 | 町名番地 | 文字列 | |
customer_address3 | ビル・建物名 | 文字列 | |
total_price | 商品総額 | 数値 | 8000 |
tax | 消費税 | 整数 | 800 |
shipping_cost | 送料 | 整数 | 540 |
COD_cost | 決済手数料 | 整数 | 0 |
final_price | 受注総額 | 整数 | 9340 |
use_point | ポイント利用 | 整数 | 0 |
get_point | ポイント獲得 | 整数 | 0 |
payment | 決済方法 | 文字列 | 銀行振込 |
payment_at | 決済確認日 | 文字列 | |
customer_customs | 会員カスタム項目 | 配列 | 会員カスタム項目を参照 |
enquete1 | アンケート1 | 文字列 | |
enquete2 | アンケート2 | 文字列 | |
enquete3 | アンケート3 | 文字列 | |
enquete4 | アンケート4 | 文字列 | |
enquete5 | アンケート5 | 文字列 | |
customer_message | 連絡事項 | 文字列 | |
memo | メモ | 文字列 | |
customs | 受注カスタム項目 | 配列 | 受注カスタム項目を参照 |
admin_message | お客様への連絡事項 | 文字列 | |
ordered_at | 受注日時 | 文字列 | 2020-12-10 14:05:28 |
status | 対応状況 | 文字列 | 新規注文 |
order_totals | 税別内訳 | 配列 | 税別内訳を参照 |
logistics | 出荷情報 | 配列 | 出荷情報を参照 |
order_products | 受注商品情報 | 配列 | 受注商品情報を参照 |
税別内訳
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
tax_rate | 税率 | 数値 | 0.1 |
total | 税別総額 | 整数 | 8491 |
tax | 税額 | 整数 | 849 |
total_incl_tax | 税別総額 | 整数 | 9340 |
出荷情報
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
id | 配送ID | 整数 | 20000004 |
delivery_code | 送り状番号 | 文字列 | |
shipment_code | 配送管理番号 | 文字列 | |
destination_code | 配送先コード | 文字列 | |
shipping_group_id | 配送グループID | 整数 | 1 |
comp_name | 会社名 | 文字列 | Bカートサポートセンター |
department | 部署名 | 文字列 | お客様サポート |
name | 担当者名 | 文字列 | Bカート |
pref | 都道府県 | 文字列 | 京都府 |
zip | 郵便番号 | 文字列 | 600-8412 |
address1 | 市区町村 | 文字列 | 京都市下京区二帖半敷町 |
address2 | 町名番地 | 文字列 | 646番地 |
address3 | ビル建物名 | 文字列 | ダイマルヤ四条烏丸ビル5F |
tel | 電話番号 | 文字列 | 075-361-1171 |
due_date | 配送希望日 | 日付 | |
due_time | 配送時間帯 | 文字列 | |
shipment_date | 発送日 | 日付 | |
memo | メモ | 文字列 | |
arrival_date | 納品日 | 日付 | |
status | 発送状況 | 文字列 | 未発送 |
受注商品情報
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
id | 受注商品ID | 整数 | 6 |
order_id | 受注ID | 整数 | 4 |
logistics_id | 出荷ID | 整数 | 20000004 |
item_type | 商品タイプ | 文字列 | product |
product_id | 商品ID | 整数 | 2 |
main_no | 商品管理番号 | 文字列 | SF-001 |
product_name | 商品名 | 文字列 | クラシックソファー(一人がけ) |
product_customs | 商品カスタム項目 | 配列 | 商品カスタム項目を参照 |
product_set_id | セットID | 整数 | 5 |
product_no | 品番 | 文字列 | SF-001-01-O |
jan_code | 文字列 | 490121212 | |
set_name | セット名 | 文字列 | 単品販売 カラー:オーク |
location_no | ロケーションNo. | 文字列 | |
shipping_size | 配送サイズ | 文字列 | 0 |
unit_price | 単価 | 数値 | 8000 |
set_quantity | 入数 | 整数 | 1 |
set_unit | 文字列 | 脚 | |
product_set_customs | 商品セットカスタム項目 | 配列 | 商品セットカスタム項目を参照 |
options | オプション | 文字列 | |
order_pro_count | 注文数 | 整数 | 1 |
tax_type_id | 消費税タイプID | 整数 | 1 |
tax_incl | 内税フラグ | 整数 | 0 |
tax_rate | 税率 | 数値 | 0.1 |
別配送先情報
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
id | 別配送先ID | 整数 | 1 |
destination_code | 配送コード | 文字列 | 1000 |
customer_id | 会員ID | 整数 | 9999 |
comp_name | 会社名 | 文字列 | Bカート株式会社 |
department | 部署名 | 文字列 | 京都支店営業部 |
name | 担当者名 | 文字列 | 田中 一郎 |
zip | 郵便番号 | 文字列 | 600-8412 |
pref | 都道府県 | 文字列 | 京都府 |
address1 | 市区町村 | 文字列 | 京都市下京区 |
address2 | 町名番地 | 文字列 | 二帖半敷町2 |
address3 | ビル建物名 | 文字列 | |
tel | 電話番号 | 文字列 | 000-0000-0000 |
会員カスタム項目
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
field_id | 会員カスタム項目ID | 整数 | 1 |
value | 値 | 文字列 | カスタム1 |
受注カスタム項目
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
field_id | 受注カスタム項目ID | 整数 | 1 |
value | 値 | 文字列 | カスタム1 |
商品カスタム項目
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
field_id | 商品カスタム項目ID | 整数 | 1 |
value | 値 | 文字列 | カスタム1 |
商品セットカスタム項目
フィールド名 | 日本語名称 | 型 | サンプル |
---|---|---|---|
field_id | 商品セットカスタム項目ID | 整数 | 1 |
value | 値 | 文字列 | カスタム1 |