Box Sign: カスタム通知と新しいWebhook

Yuko Taniguchi
Box Developer Japan Blog
21 min readJun 21, 2024
Image by vectorjuice on Freepik

Box Sign関連の新しいWebhookは、通知の抑制機能と組み合わせることができるようになりました。これにより、アプリケーションからユーザーに署名プロセスについて通知する方法を全面的に制御できます。

デフォルトでは、Box Signはbox.comドメイン下のユーザーにメールで通知を送信します。これらのメールはカスタマイズできますが、多くのお客様は、独自のメールシステムを使用したり、独自の通知システムによるメール以外の方法を使用したりしたいと考えています。

この記事では、Pythonの次世代SDKを使用したデフォルト通知の抑制の実装について詳しく説明します。

⚠️ Boxのメール通知を抑制することを選択した場合、組織は、署名プロセスにおいて適切なタイミングで (かつ適切な内容で) すべての通知を署名者に確実に配信する責任を負うことになります。また、組織は、該当する場合に、使用される配信方法に対する署名者の同意を得る必要があることを含め、適用される法律と規制に従う必要もあります。

重要なのはWebhook

以下の例では、Box Signの通知を抑制した場合、アプリケーションは署名リクエストの状態に変化が生じているかどうかを判断する必要があります。これは、リクエストのステータスをポーリングすることで可能ですが、あまり実用的ではありません。Webhookを使用して、アプリに変更が通知されるようにしたほうが理想的です。

このために、Boxでは、Box Signに関連したWebhookを新しく3つ作成しました。

  • SIGN_REQUEST.SIGNATURE_REQUESTED — 個々の署名者に対して署名リクエストが作成されたとき
  • SIGN_REQUEST.SIGNER_SIGNED — 個々の署名者が署名を完了したとき
  • SIGN_REQUEST.ERROR_FINALIZING — 署名リクエストの最後のステップでエラーが発生したとき (たとえば、システムで署名済みドキュメントを生成できない場合)

この演習では、Webhookペイロードを表示できる優れたツールwebhook.siteを使用して、Box Sign関連のほとんどのWebhookを取得します。

webhook.siteから一意のURLを取得した後、関連するアプリケーションでWebhookを作成します。

フォルダを監視するSign関連のすべてのWebhook

All Sign-related webhooks monitoring a folder

注: アプリケーションでWebhookリクエストの信頼性を検証できるように、アプリケーションに関連付けられたWebhookキーを必ず生成する必要があります。

署名リクエスト

署名リクエストのオプションを簡略化し、通知の抑制とWebhookに重点を置くために、この演習で使用するテンプレートを作成しました。

  • Simple-PDF — 署名者が1人のサンプルドキュメント

これにより、リクエストは非常にシンプルになります。

デフォルトの通知の使用

このリクエストを見てみましょう。

curl --location 'https://api.box.com/2.0/sign_requests' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer DT...0v' \
--data-raw '{
"parent_folder": {
"id": "249194622181",
"type": "folder"
},
"template_id":"15422517-8adb-42e1-895d-bbe1cf02aafd",
"signers": [
{
"email": "barbasr+signerA@gmail.com",
"role": "signer"
}
]
}'

署名リクエストオブジェクトが返されます (簡略化されています)。

{
"is_document_preparation_needed": false,
"signers": [
{
"email": "barduinor@gmail.com",
"role": "final_copy_reader",
"suppress_notifications": false
},
{
"email": "barbasr+signera@gmail.com",
"role": "signer",
"suppress_notifications": false
}
],
"id": "ae4b3058-78b8-4526-bb21-d6582ddd383f",
"parent_folder": {
"id": "249194622181",
"name": "signed docs"
},
"name": "Simple-PDF.pdf",
"type": "sign-request",
"status": "created",
"sign_files": {
"files": [
{
"id": "1538251021756",
"name": "Simple-PDF.pdf",
}
],
"is_ready_for_download": true
},
"template_id": "15422517-8adb-42e1-895d-bbe1cf02aafd",
}

さらに、Webhookは次のペイロードを送信しました (簡略化されています)。

{
"type": "webhook_event",
"id": "4548de33-a405-47af-981b-75f722c2f7ee",
"created_at": "2024-05-22T08:10:57-07:00",
"trigger": "SIGN_REQUEST.SIGNATURE_REQUESTED",
"webhook": {
"id": "2770072773",
"type": "webhook"
},
"source": {
"id": "1538251021756",
"type": "file",
"name": "Simple-PDF.pdf",
"item_status": "active"
},
"additional_info": {
"sign_request_id": "ae4b3058-78b8-4526-bb21-d6582ddd383f",
"signer_emails": [
"barduinor@gmail.com",
"barbasr+signera@gmail.com"
],
"external_id": ""
}
}

ペイロードは、署名リクエストが作成されたことをアプリに示していることに注意してください。これには、関連付けられているドキュメント、署名者のメールアドレス、および (最も重要な) 署名リクエストIDが含まれています。

このリクエストのハッピーパスを完了すると、Webhookからさらにいくつかのリクエストが返されます。

署名者がドキュメントに署名すると、次のようになります (特定の署名者の詳細に注目してください)。

{
"type": "webhook_event",
"id": "b6bf1a5b-7346-4cda-b959-4c89d078db6f",
"created_at": "2024-05-22T08:28:56-07:00",
"trigger": "SIGN_REQUEST.SIGNER_SIGNED",
"webhook": {
"id": "2770072773",
"type": "webhook"
},
"additional_info": {
"sign_request_id": "ae4b3058-78b8-4526-bb21-d6582ddd383f",
"signer_emails": [
"barduinor@gmail.com",
"barbasr+signera@gmail.com"
],
"single_signer_event_email": "barbasr+signera@gmail.com",
"single_signer_details": {
"embed_url_external_user_id": null,
"role": "signer",
"order": 1
},
}
}

署名リクエストが完了すると、次のようになります。

{
"type": "webhook_event",
"id": "20dda22c-5862-4d4f-876c-94a266705e14",
"created_at": "2024-05-22T08:28:56-07:00",
"trigger": "SIGN_REQUEST.COMPLETED",
"webhook": {
"id": "2770072773",
"type": "webhook"
},
"created_by": {
"type": "user",
"id": "18622116055",
"name": "Rui Barbosa",
"login": "barduinor@gmail.com"
},
"additional_info": {
"sign_request_id": "ae4b3058-78b8-4526-bb21-d6582ddd383f",
"signer_emails": [
"barduinor@gmail.com",
"barbasr+signera@gmail.com"
],
"external_id": ""
}
}

簡略化されたバージョンを紹介していますが、Webhookペイロードの情報量ははるかに多くなります。ただし、情報が不足している場合は、いつでもGET /2.0/signs_requests/:sign_request_idにクエリを実行して、詳細全体を調べることができます。

通知の抑制

通知を抑制するには、署名者ごとにsuppress_notificationsフラグを設定し、embed_url_external_user_idを設定する必要があります。これらのフラグを両方とも設定しないと、APIによって404 bad requestが返されます (ユーザーにドキュメントへの署名をリクエストするために必要な署名URLを取得できないため)。

以下に例を示します。

curl --location 'https://api.box.com/2.0/sign_requests' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer DT...0v' \
--data-raw '{
"parent_folder": {
"id": "249194622181",
"type": "folder"
},
"template_id":"15422517-8adb-42e1-895d-bbe1cf02aafd",
"signers": [
{
"email": "barbasr+signerA@gmail.com",
"role": "signer",
"suppress_notifications":true
}
]
}'

次の結果が返されます。

{
"type": "error",
"code": "bad_request",
"status": 400,
"message": "Bad request",
"help_url": "https://developer.box.com/guides/api-calls/permissions-and-errors/common-errors/",
"request_id": "1fe9d1228d02f19b8efd4a3ca5b664ed9",
"context_info": {
"errors": [
{
"name": "Bad Request",
"message": "Invalid request payload input",
"reason": "invalid_parameter"
}
]
}
}

適切なリクエストは次のようになります。

curl --location 'https://api.box.com/2.0/sign_requests' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer DT...0v' \
--data-raw '{
"parent_folder": {
"id": "249194622181",
"type": "folder"
},
"template_id":"15422517-8adb-42e1-895d-bbe1cf02aafd",
"signers": [
{
"email": "barbasr+signerA@gmail.com",
"role": "signer",
"suppress_notifications":true,
"embed_url_external_user_id":"my_id"
}
]
}'

次の結果が返されます。

{
"is_document_preparation_needed": false,
"signers": [
{
"email": "barduinor@gmail.com",
"role": "final_copy_reader",
"embed_url": null,
"iframeable_embed_url": null,
"suppress_notifications": false
},
{
"email": "barbasr+signera@gmail.com",
"role": "signer",
"embed_url_external_user_id": "my_id",
"embed_url": "https://app.box.com/sign/document/e8715868-e88d-4f98-8da6-6de91c73ff08/1060eef0a2230e928ad43c868d08d6807d5bbe42e642579b277975b1cc8725c6/",
"iframeable_embed_url": "https://app.box.com/embed/sign/document/e8715868-e88d-4f98-8da6-6de91c73ff08/1060eef0a2230e928ad43c868d08d6807d5bbe42e642579b277975b1cc8725c6/",
"suppress_notifications": true
}
],
"id": "e8715868-e88d-4f98-8da6-6de91c73ff08",
"name": "Simple-PDF (1).pdf",
"type": "sign-request",
"status": "created",
"template_id": "15422517-8adb-42e1-895d-bbe1cf02aafd",
"external_system_name": null
}

上記のとおり、署名者が実際にドキュメントに署名できるembed_urlを生成できました。この先、ユーザーにとって処理が容易になるかどうかはアプリ次第です。

また、Webhookから別のコールバックも生成しました。

{
"type": "webhook_event",
"id": "57457ae5-7aae-4624-b4bb-75c1a3b4d6e2",
"created_at": "2024-05-22T08:53:42-07:00",
"trigger": "SIGN_REQUEST.SIGNATURE_REQUESTED",
"webhook": {
"id": "2770072773",
"type": "webhook"
},
"additional_info": {
"sign_request_id": "e8715868-e88d-4f98-8da6-6de91c73ff08",
"signer_emails": [
"barduinor@gmail.com",
"barbasr+signera@gmail.com"
],
"external_id": ""
}
}

このペイロードは、通知を抑制する前のペイロードと大差ありません。通知を送信するために必要な情報 (署名者など) がすべて揃っていないため、アプリケーションは、署名リクエストからさらに詳細を取得することになります。

署名リクエストを完了するための方法の1つとして、embed_urlを開きます。

署名リクエストの完了

ユーザーが署名リクエストを完了すると、さらにいくつかのWebhookコールバックが返されます。

特定のユーザーが署名すると、次のようになります。

{
"type": "webhook_event",
"id": "9ff2eebd-da90-4609-8ffd-e6c27eb46c01",
"created_at": "2024-05-22T09:07:25-07:00",
"trigger": "SIGN_REQUEST.SIGNER_SIGNED",
"webhook": {
"id": "2770072773",
"type": "webhook"
},
"additional_info": {
"sign_request_id": "e8715868-e88d-4f98-8da6-6de91c73ff08",
"signer_emails": [
"barduinor@gmail.com",
"barbasr+signera@gmail.com"
],
"external_id": "",
"single_signer_event_email": "barbasr+signera@gmail.com",
"single_signer_details": {
"embed_url_external_user_id": "my_id",
"role": "signer",
"order": 1
}
}
}

署名リクエストのプロセスが完了すると、次のようになります。

{
"type": "webhook_event",
"id": "2cb045f0-553e-4cb3-931d-aef208b4e3a0",
"created_at": "2024-05-22T09:07:25-07:00",
"trigger": "SIGN_REQUEST.COMPLETED",
"webhook": {
"id": "2770072773",
"type": "webhook"
},
"additional_info": {
"sign_request_id": "e8715868-e88d-4f98-8da6-6de91c73ff08",
"signer_emails": [
"barduinor@gmail.com",
"barbasr+signera@gmail.com"
],
"external_id": ""
}
}

ハッピーパス以外の場合

署名者がドキュメントへの署名を拒否した場合はどうなるでしょうか。

上記と同様のリクエストを使用した場合、署名リクエストが作成され、Webhookによってコールバックが開始されると、SIGN_REQUEST.SIGNATURE_REQUESTEDが返されます。

署名者がリクエストを拒否すると、SIGN_REQUEST.DECLINEDが返されます。詳細を見てみましょう。

{
"type": "webhook_event",
"id": "6b922242-d43b-4213-84da-bb1ed72e7c0b",
"created_at": "2024-05-22T10:01:20-07:00",
"trigger": "SIGN_REQUEST.DECLINED",
"webhook": {
"id": "2770072773",
"type": "webhook"
},
"additional_info": {
"sign_request_id": "7390f653-ffdf-45c3-9d5d-7255b1c0496b",
"signer_emails": [
"barduinor@gmail.com",
"barbasr+signer_b@gmail.com"
],
"external_id": "",
"single_signer_event_email": "barbasr+signer_b@gmail.com",
"single_signer_details": {
"embed_url_external_user_id": "my_id",
"role": "signer",
"order": 1
},
"signer_decision_additional_info": "I refuse to sign this document"
}
}

通知をオンに戻し、無効なメールアドレスにリクエストを送信すると、どうなるでしょうか。

curl --location 'https://api.box.com/2.0/sign_requests' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YM...Dg' \
--data-raw '{
"parent_folder": {
"id": "249194622181",
"type": "folder"
},
"template_id":"15422517-8adb-42e1-895d-bbe1cf02aafd",
"signers": [
{
"email": "barbasr+signer_b@example.com",
"role": "signer",
"suppress_notifications":false
}
]
}'

APIからは署名のレスポンス、WebhookからはSIGN_REQUEST.SIGNATURE_REQUESTEDが返されます。

ただし、数秒後には、SIGN_REQUEST.SIGNER_EMAIL_BOUNCEDとともに、問題が発生している署名者を示す追加の詳細が表示されます。

{
"type": "webhook_event",
"id": "3b0c0931-e226-4251-80f0-cb6dc57a787d",
"created_at": "2024-05-22T10:09:24-07:00",
"trigger": "SIGN_REQUEST.SIGNER_EMAIL_BOUNCED",
"webhook": {
"id": "2770072773",
"type": "webhook"
},
"additional_info": {
"sign_request_id": "bd4ba858-a047-4ff3-b53f-8b9c30b0e5e0",
"signer_emails": [
"barduinor@gmail.com",
"barbasr+signer_b@example.com"
],
"external_id": "",
"single_signer_event_email": "barbasr+signer_b@example.com",
"single_signer_details": {
"embed_url_external_user_id": null,
"role": "signer",
"order": 1
}
}
}

その他のWebhook

テスト環境での複製が難しいため、まだトリガーしていないWebhookもいくつかあります。それには、以下が含まれます。

  • SIGN_REQUEST.EXPIRED — 署名リクエストで設定された有効期限を経過したとき
  • SIGN_REQUEST.ERROR_FINALIZING — 署名リクエストの最後のステップで内部エラーが発生したとき (たとえば、最終的な署名済みドキュメントの作成中にエラーが発生した場合)

まとめ

Sign関連のWebhookは、それだけで、署名リクエスト内の状態の変化をアプリケーションが認識できるようにします。ワークフローの進捗に合わせて、アプリはその変化に対応することで、プロセス全体でユーザーの認識を改善できます。

アイデア、コメント、フィードバックがある場合は、コミュニティフォーラム (英語のみ) にコメントをお送りください。

--

--