Webhook について

Webhook(ウェブフック)とはBカートで発生した各種イベントを利用者の用意したシステムへ通知を行う仕組みです。
エンドポイントを登録すると、指定したイベント(注文登録や変更時など)が発生した場合にエンドポイントURLにデータがPOSTされることになります。
ご利用いただくにはエンドポイントでデータを受信し、設定したSecretの正当性を確認するシステムをご用意いただく必要があるため開発者様向けの内容となっております。
※ webhookはリアルタイムでの連携が実現可能となりますが、配信が必ず保証されているわけではございません。注意事項の詳細はWebhookの制約についてをご確認ください。

インボイス(適格請求書)設定の有効/無効により、仕様が変わります。
詳細は「インボイス(適格請求書)設定によるAPIへの影響について」をご確認ください。

 

 

 

 

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','GET'])
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 ビル・建物名 文字列
email メールアドレス 文字列 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