esaでは、記事やコメントの投稿・更新時に指定されたURLに対してHTTPリクエストを送ることができます。
チームのOwnerが https://[your-team].esa.io/team/webhooks から各種Webhookを設定することができます
POST
20秒(open timeout: 15秒)
1回
※ リクエストがタイムアウトなどで失敗した際、同じリクエストが複数発行される場合があります。その場合は後述する X-Esa-Delivery ヘッダを確認することで同一のリクエストかどうかを判断することができます。
application/json
esa-Hookshot/v1
例: 1234
リクエストに対する一意なIDです。
後述するリクエストボディの値の改善を防ぐためにSignatureを指定できます。Generic webhookの設定画面で Secret (optinal) を設定した場合にこのヘッダーが追加されます。
例:
my_secret_key
{"kind":"post_create","post":{"name": "たいとる"}}(実際はPayloadの例のような値となります)上記の場合、esaのサーバはまず、このPayload({"kind":"post_create","post":{"name": "たいとる"}})に対して、SHA-256ハッシュ関数を利用し、my_secret_keyを共有キーとした以下のようなHMACの値を生成します。
5c2cd89667226539b34ea930781b8bf3e7f1236da7624eee6b748cd52899f91f
esaのサーバは次に、Webhookで指定したURLに対してHTTP_X_ESA_SIGNATUREヘッダに
HMACの値の先頭にsha256=という文字列を付与した以下のような文字列を設定し、リクエストを発行します。
sha256=5c2cd89667226539b34ea930781b8bf3e7f1236da7624eee6b748cd52899f91f
Webhookに設定したURLに対応するエンドポイントでは、HTTP_X_ESA_SIGNATUREヘッダの値のsha256=より後の値を抜き出し、以下のようにHMACの値を生成し、Payloadに改ざんがないかどうかを確認します。
# 環境変数の SECRET_TOKEN には、my_secret_key という値が入っているとする
payload = request.body.read # {"kind":"post_create","post":{"name": "たいとる"}}
received_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload)
# このsignatureと
if Rack::Utils.secure_compare(received_signature, request.env['HTTP_X_ESA_SIGNATURE'])
# good
else
# ng
end
echo -n '{"kind":"post_create","post":{"name": "たいとる"}}' \
| openssl dgst -sha256 -hmac "my_secret_key"
see also: ppworks/rack-esa_webhooks
json 形式で payload が渡されます。
{
"kind": "post_create",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Create post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "post_update",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Update post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253",
"diff_url": "https://example.esa.io/posts/1253/revisions/3"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "post_archive",
"team": {
"name": "esa"
},
"post": {
"name": "Archived/たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Archived!",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "post_delete",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"wip": false,
"number": 1253
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "post_start_sharing",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Create post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
},
"sharing": {
"url": "https://esa-pages.io/p/sharing/105/posts/37/587eedb862cde79c9a79.html"
}
}
{
"kind": "post_stop_sharing",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Create post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "comment_create",
"team": {
"name": "esa"
},
"post": {
"name": "Archived/たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Update post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253#comment-6385"
},
"comment": {
"body_md": "こめんと",
"body_html": "<p>こめんと</p>\n"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "member_join",
"team": {
"name": "esa"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
# Generic Webhookの概要
esaでは、記事やコメントの投稿・更新時に指定されたURLに対してHTTPリクエストを送ることができます。
# 設定方法
チームのOwnerが https://[your-team].esa.io/team/webhooks から各種Webhookを設定することができます
# リクエストの詳細
## HTTPメソッド
`POST`
## タイムアウト
20秒(open timeout: 15秒)
## リトライ
1回
※ リクエストがタイムアウトなどで失敗した際、同じリクエストが複数発行される場合があります。その場合は後述する `X-Esa-Delivery` ヘッダを確認することで同一のリクエストかどうかを判断することができます。
## リクエストヘッダー
### Content-Type
`application/json`
### User-Agent
`esa-Hookshot/v1`
### X-Esa-Delivery
例: `1234`
リクエストに対する一意なIDです。
### X-Esa-Signature
後述するリクエストボディの値の改善を防ぐためにSignatureを指定できます。Generic webhookの設定画面で `Secret (optinal)` を設定した場合にこのヘッダーが追加されます。
例:
- Secretの値が`my_secret_key`
- Payloadの値が`{"kind":"post_create","post":{"name": "たいとる"}}`(実際は[Payloadの例](https://docs.esa.io/posts/37#json%20payload)のような値となります)
上記の場合、esaのサーバはまず、このPayload(`{"kind":"post_create","post":{"name": "たいとる"}}`)に対して、SHA-256ハッシュ関数を利用し、`my_secret_key`を共有キーとした以下のようなHMACの値を生成します。
`5c2cd89667226539b34ea930781b8bf3e7f1236da7624eee6b748cd52899f91f`
esaのサーバは次に、Webhookで指定したURLに対して`HTTP_X_ESA_SIGNATURE`ヘッダに
HMACの値の先頭に`sha256=`という文字列を付与した以下のような文字列を設定し、リクエストを発行します。
`sha256=5c2cd89667226539b34ea930781b8bf3e7f1236da7624eee6b748cd52899f91f`
Webhookに設定したURLに対応するエンドポイントでは、`HTTP_X_ESA_SIGNATURE`ヘッダの値の`sha256=より後の値`を抜き出し、以下のようにHMACの値を生成し、Payloadに改ざんがないかどうかを確認します。
```ruby:rackでHMACの値を生成し、ヘッダと比較する例
# 環境変数の SECRET_TOKEN には、my_secret_key という値が入っているとする
payload = request.body.read # {"kind":"post_create","post":{"name": "たいとる"}}
received_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload)
# このsignatureと
if Rack::Utils.secure_compare(received_signature, request.env['HTTP_X_ESA_SIGNATURE'])
# good
else
# ng
end
```
```bash:コマンドラインでHMACの値を生成する例
echo -n '{"kind":"post_create","post":{"name": "たいとる"}}' \
| openssl dgst -sha256 -hmac "my_secret_key"
```
see also: [ppworks/rack-esa_webhooks](https://github.com/ppworks/rack-esa_webhooks)
## リクエストボディ
json 形式で payload が渡されます。
### 記事作成時(kind: "post_create")
```json
{
"kind": "post_create",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Create post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
```
### 記事更新時(kind: "post_update")
```json
{
"kind": "post_update",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Update post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253",
"diff_url": "https://example.esa.io/posts/1253/revisions/3"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
```
### 記事archive時(kind: "post_archive")
```json
{
"kind": "post_archive",
"team": {
"name": "esa"
},
"post": {
"name": "Archived/たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Archived!",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
```
### 記事削除時(kind: "post_delete")
```json
{
"kind": "post_delete",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"wip": false,
"number": 1253
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
```
### 外部公開の開始時(kind: "post_start_sharing")
```json
{
"kind": "post_start_sharing",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Create post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
},
"sharing": {
"url": "https://esa-pages.io/p/sharing/105/posts/37/587eedb862cde79c9a79.html"
}
}
```
### 外部公開の停止時(kind: "post_stop_sharing")
```json
{
"kind": "post_stop_sharing",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Create post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
```
### コメント作成時(kind: "comment_create")
```json
{
"kind": "comment_create",
"team": {
"name": "esa"
},
"post": {
"name": "Archived/たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Update post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253#comment-6385"
},
"comment": {
"body_md": "こめんと",
"body_html": "<p>こめんと</p>\n"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
```
### メンバー追加時(kind: "member_join")
```json
{
"kind": "member_join",
"team": {
"name": "esa"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
```
esaでは、記事やコメントの投稿・更新時に指定されたURLに対してHTTPリクエストを送ることができます。
チームのOwnerが https://[your-team].esa.io/team/webhooks から各種Webhookを設定することができます
POST
20秒(open timeout: 15秒)
1回
※ リクエストがタイムアウトなどで失敗した際、同じリクエストが複数発行される場合があります。その場合は後述する X-Esa-Delivery ヘッダを確認することで同一のリクエストかどうかを判断することができます。
application/json
esa-Hookshot/v1
例: 1234
リクエストに対する一意なIDです。
後述するリクエストボディの値の改善を防ぐためにSignatureを指定できます。Generic webhookの設定画面で Secret (optinal) を設定した場合にこのヘッダーが追加されます。
例:
my_secret_key
{"kind":"post_create","post":{"name": "たいとる"}}(実際はPayloadの例のような値となります)上記の場合、esaのサーバはまず、このPayload({"kind":"post_create","post":{"name": "たいとる"}})に対して、SHA-256ハッシュ関数を利用し、my_secret_keyを共有キーとした以下のようなHMACの値を生成します。
5c2cd89667226539b34ea930781b8bf3e7f1236da7624eee6b748cd52899f91f
esaのサーバは次に、Webhookで指定したURLに対してHTTP_X_ESA_SIGNATUREヘッダに
HMACの値の先頭にsha256=という文字列を付与した以下のような文字列を設定し、リクエストを発行します。
sha256=5c2cd89667226539b34ea930781b8bf3e7f1236da7624eee6b748cd52899f91f
Webhookに設定したURLに対応するエンドポイントでは、HTTP_X_ESA_SIGNATUREヘッダの値のsha256=より後の値を抜き出し、以下のようにHMACの値を生成し、Payloadに改ざんがないかどうかを確認します。
# 環境変数の SECRET_TOKEN には、my_secret_key という値が入っているとする
payload = request.body.read # {"kind":"post_create","post":{"name": "たいとる"}}
received_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload)
# このsignatureと
if Rack::Utils.secure_compare(received_signature, request.env['HTTP_X_ESA_SIGNATURE'])
# good
else
# ng
end
echo -n '{"kind":"post_create","post":{"name": "たいとる"}}' \
| openssl dgst -sha256 -hmac "my_secret_key"
see also: ppworks/rack-esa_webhooks
json 形式で payload が渡されます。
{
"kind": "post_create",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Create post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "post_update",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Update post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253",
"diff_url": "https://example.esa.io/posts/1253/revisions/3"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "post_archive",
"team": {
"name": "esa"
},
"post": {
"name": "Archived/たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Archived!",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "post_delete",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"wip": false,
"number": 1253
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "post_start_sharing",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Create post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
},
"sharing": {
"url": "https://esa-pages.io/p/sharing/105/posts/37/587eedb862cde79c9a79.html"
}
}
{
"kind": "post_stop_sharing",
"team": {
"name": "esa"
},
"post": {
"name": "たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Create post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "comment_create",
"team": {
"name": "esa"
},
"post": {
"name": "Archived/たいとる",
"body_md": "ほんぶん",
"body_html": "<p>ほんぶん</p>\n",
"message": "Update post.",
"wip": false,
"number": 1253,
"url": "https://example.esa.io/posts/1253#comment-6385"
},
"comment": {
"body_md": "こめんと",
"body_html": "<p>こめんと</p>\n"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}
{
"kind": "member_join",
"team": {
"name": "esa"
},
"user": {
"icon": {
"url": "https://img.esa.io/uploads/production/users/1/icon/402685a258cf2a33c1d6c13a89adec92.png",
"thumb_s": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_s_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_ms": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_ms_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_m": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_m_402685a258cf2a33c1d6c13a89adec92.png"
},
"thumb_l": {
"url": "https://img.esa.io/uploads/production/users/1/icon/thumb_l_402685a258cf2a33c1d6c13a89adec92.png"
}
},
"name": "Atsuo Fukaya",
"screen_name": "fukayatsu"
}
}