Box Signの使用

Yuko Taniguchi
Box Developer Japan Blog
26 min readNov 24, 2023

この記事では、Box Platformを使用してドキュメントに署名する方法について説明します。特に非構造化ドキュメントについて、また、すべてのユースケースに共通するBox Sign機能の大半も取り上げます。

今後の記事では、テンプレートを使用した署名、構造化されたドキュメント、複雑なユースケースに焦点を当てる予定です。

このワークショップは、こちらのGitHubリポジトリにあるコードサンプル一式を使用して進めることができます。ここでは、Box Platformの次世代のPython SDKを使用します。

非構造化ドキュメント

ユーザーがドキュメントをアップロードし、誰にでもそのドキュメントへの署名を依頼できる、ある種のドキュメント管理アプリを想像してみてください。この場合、アプリは、署名するドキュメントと署名する必要がある人を認識しますが、署名やそのプロパティ (名前、日付、イニシャルなど) を配置する場所は認識しません。

これは、テンプレートや構造化されたドキュメントを使用する場合とは対照的です。これらを使用する場合、アプリは、署名プロパティの内容や場所を認識します。

この場合、各ドキュメントに異なる構造を使用できるため、常にis_document_preparation_neededフラグを使用することをお勧めします。これを使用すると、署名者がリクエストを受け取る前に、送信者はドキュメントのプロパティを選択してドキュメント内に配置できるようになります。

次のメソッドを考えてみましょう。

def sign_doc_single(
client: Client,
document_id: str,
destination_folder_id: str,
signer_email: str,
prep_needed: bool = False,
) -> SignRequest:
"""Single doc sign by single signer"""

# Sign request params
source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE)
destination_folder = FolderMini(
id=destination_folder_id, type=FolderBaseTypeField.FOLDER
)
signer = SignRequestCreateSigner(signer_email)
# sign document
sign_request = client.sign_requests.create_sign_request(
signers=[signer],
parent_folder=destination_folder,
source_files=[source_file],
is_document_preparation_needed=prep_needed,
)

return sign_request

次のように使用します。

def main():
"""Simple script to demonstrate how to use the Box SDK"""
conf = ConfigOAuth()
client = get_client_oauth(conf)

# Simple sign a pdf request with preparation
sign_pdf_prep = sign_doc_single(
client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, True
)
check_sign_request(sign_pdf_prep)
if sign_pdf_prep.prepare_url is not None:
open_browser(sign_pdf_prep.prepare_url)

上記のスクリプトでは、ドキュメント準備のURLが署名リクエストによって生成された場合、アプリがそのためにブラウザを開くことに注意してください。その後、ユーザーは次のようなさまざまな署名プロパティを適用できます。

署名用ドキュメントの準備

署名をリクエストしたユーザー (送信者) は、署名プロパティをドキュメント内の適切な位置にドラッグします。署名パッドだけでなく、さまざまなプロパティを選択できます。

これが完了すると、署名リクエストがメールで署名者に送信されます。実際の署名ページは次のようになります。

ドキュメントへの署名

この場合、is_document_preparation_needを渡さなければ、署名者は、署名パッドを好きな場所に配置し、他のプロパティを使用する (または使用しない) こともできます。もちろん、ユーザーがこれを正しく行わない場合も考えられます。非構造化ドキュメントの場合、アプリは常にこのフラグを使用し、ドキュメント準備のURLを呼び出す必要があります。

Box Signの機能

典型的な署名アプリケーションはもう少し複雑だと思われるかもしれませんが、どこかから始めなければなりません。

より複雑なアプリケーションのためにBox Signが提供する機能を見てみましょう。

これらは、非構造化ドキュメントだけでなく、どのような署名リクエストやユースケースにも当てはまることにご注意ください。

複数の署名者

複数の人に署名してもらう必要があるドキュメントがある場合はどうなるでしょうか。これは、2つ以上の事業体の間で結ばれる契約でよく見られます。

複数の署名者を設定すると、署名プロセスには、署名者がドキュメントに署名する順序という別の要素が導入されます。

順序を指定しない場合、リクエストは全員に同時に送信されます。さらに、すべての関係者がドキュメントに署名すると、すべての署名を含むコピーを受け取ります。

順序を指定すると、署名リクエストは最初の署名者に送信され、最初の署名者がドキュメントに署名した場合にのみ、このリクエストは2番目の署名者に送信されます (以降も同様)。

大学と学生の間で交わされる奨学金の契約の例を使用してこの仕組みを見てみましょう。この場合は、教育機関/教師が最初にドキュメントに署名する必要があります。

このためのメソッドを作成します。

def sign_contract(
client: Client,
document_id: str,
destination_folder_id: str,
institution_email: str,
student_email: str,
prep_needed: bool = False,
) -> SignRequest:
"""Sign contract"""

# Sign request params
source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE)
destination_folder = FolderMini(
id=destination_folder_id, type=FolderBaseTypeField.FOLDER
)
# signers
institution = SignRequestCreateSigner(
email=institution_email,
role=SignRequestCreateSignerRoleField.SIGNER,
order=1,
)
student = SignRequestCreateSigner(
email=student_email,
role=SignRequestCreateSignerRoleField.SIGNER,
order=2,
)
# create sign request
sign_request = client.sign_requests.create_sign_request(
signers=[institution, student],
parent_folder=destination_folder,
source_files=[source_file],
is_document_preparation_needed=prep_needed,
)
return sign_request

次のように使用します。

def main():
...

# Multiple signers
sign_contract_multi = sign_contract(
client,
CONTRACT,
SIGN_DOCS_FOLDER,
institution_email=SIGNER_A,
student_email=SIGNER_B,
prep_needed=True,
)
if sign_contract_multi.prepare_url is not None:
open_browser(sign_contract_multi.prepare_url)

ブラウザが開き、ドキュメント準備ページが表示されます。

この時点で2人の署名者が設定され、順序もすでに指定されていることに注目してください。また、色は、署名者を識別するためにも重要であり (この場合、教育機関は青、学生は緑)、どの署名者にどの署名パッド、名前、日付が属しているかを特定します。

これまでと同様、署名パッド、フルネーム、日付をドキュメント内の適切な場所にドラッグし、[リクエストの送信] をクリックします。

契約書の準備

署名リクエストの詳細を確認すると、次のように表示されます。

最初のリクエストは送信済みであるものの、2番目のリクエストは最初のリクエストが完了するのを待っていることを示します。

先に進み、両方の署名者の署名プロセスを完了します。

2番目のリクエストを受け取った時点で、すでに最初の署名者は署名済みです。

署名リクエストの再送信

署名者がメールを受信しなかったらどうなるでしょうか。また、メールを紛失したり、署名者が誤ってメールを削除したりした場合はどうなるでしょうか。

署名リクエストメールは、手動でも、自動再送信オプションをオンにしても、署名者に再送信できます。

自動再送信オプションを使用すると、ドキュメントにまだ署名していない署名者に対して3日後、8日後、13日後、18日後にリマインダメールが送信されます。

また、署名リクエストメールを署名者に手動で再送信することもできます。それには、sign_requestsオブジェクトでresend_sign_requestメソッドを呼び出します。

これは10分間に1回しか実行できません。

手動によるリマインダの送信

例を以下に示します。

def sign_send_reminder(client: Client, sign_request_id: str):
"""Send reminder to signers"""
sign_request = client.sign_requests.resend_sign_request(sign_request_id)
return sign_request

自動リマインダの送信

自動リマインダの送信を有効にするには、are_reminders_enabledパラメータをTrueに設定するだけです。

以下に例を示します。

def sign_doc_single_more_options(
client: Client,
document_id: str,
destination_folder_id: str,
signer_email: str,
prep_needed: bool = False,
auto_reminder: bool = False,
) -> SignRequest:
"""Single doc sign by single signer"""

# Sign request params
source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE)
destination_folder = FolderMini(
id=destination_folder_id, type=FolderBaseTypeField.FOLDER
)
# signer
signer = SignRequestCreateSigner(signer_email)
# sign document
sign_request = client.sign_requests.create_sign_request(
signers=[signer],
parent_folder=destination_folder,
source_files=[source_file],
is_document_preparation_needed=prep_needed,
are_reminders_enabled=auto_reminder,
)
return sign_request

署名リクエストの有効期限

場合によっては、署名リクエストの有効期限を設定する必要があります。

たとえば、30日間有効なサービスの見積もりを想像してみてください。この提案書には期日までに署名する必要があり、署名しなかった場合、この署名リクエストは無効になります。

必要なのは、days_validパラメータを渡すことだけです。

以下に例を示します。

def sign_doc_single_more_options(
...

days_valid: int = None,
) -> SignRequest:
...

# sign document
sign_request = client.sign_requests.create_sign_request(
...

days_valid=days_valid,
)

return sign_request

リダイレクトURLのカスタマイズ

多くの場合、会社では、ドキュメントに署名したユーザーを特定のウェブページ (お礼のページやオンボーディングページなど) にリダイレクトしたいと考えていることがあります。これらの要件に対応するための機能は2つあります。

署名者がプロセスを完了すると、ウェブページにリダイレクトできます。署名者が署名リクエストを拒否した場合も同様です。

これらのページは、redirect_urlパラメータとdecline_redirect_urlパラメータを渡すことでカスタマイズできます。

以下に例を示します。

def sign_doc_single_more_options(
...

redirect_url: str = None,
declined_redirect_url: str = None,
) -> SignRequest:
...

# sign document
sign_request = client.sign_requests.create_sign_request(
...

redirect_url=redirect_url,
declined_redirect_url=declined_redirect_url,
)

return sign_request

これを試してみましょう。次のコードをmainメソッドに追加します。

def main():
...

# Sign with redirects
sign_with_redirects = sign_doc_single_more_options(
client,
SIMPLE_PDF,
SIGN_DOCS_FOLDER,
SIGNER_A,
prep_needed=False,
redirect_url="https://forum.box.com/",
declined_redirect_url="https://developer.box.com/",
)
check_sign_request(sign_with_redirects)

署名すると、Boxのフォーラムのページにリダイレクトされます。拒否すると、Boxの開発者向けページにリダイレクトされます。

メールメッセージのカスタマイズ

署名者に送信されるメールメッセージをカスタマイズするには、email_subjectパラメータとemail_messageパラメータを渡します。以下に例を示します。

def sign_doc_single_more_options(
client: Client,
...

email_subject: str = None,
email_message: str = None,
) -> SignRequest:
...

# sign document
sign_request = client.sign_requests.create_sign_request(
...

email_subject=email_subject,
email_message=email_message,
)

return sign_request

どちらのパラメータにもシンプルな文字列を使用できますが、email_messageパラメータには、いくつか制限があるもののHTMLも使用できます。

一部のHTMLタグが使用できます。また、メッセージに含まれるリンクは、メールではハイパーリンクに変換されます。メッセージには、aabbracronymbblockquotecodeemiulliolstrongなどのhtmlタグを含めることができます。

テキストとHTMLの比率が高すぎると、メールはスパムフィルタに引っかかったり、切り取られたりする可能性があることに注意してください。

これらのタグでは、独自のスタイルは許可されていません。

このフィールドが渡されない場合は、デフォルトのメッセージが使用されます。

次のコードをテストしましょう。

def main():
...

# Sign with custom email subject
sign_custom_email_subject = sign_doc_single_more_options(
client,
SIMPLE_PDF,
SIGN_DOCS_FOLDER,
SIGNER_A,
prep_needed=False,
email_subject="All we need is your signature to get started",
)
check_sign_request(sign_custom_email_subject)

署名リクエストのセキュリティ

メールは危険性が高く、簡単に侵害される可能性があります。ドキュメントへの署名に電話認証またはパスワードを使用するよう署名者に要請することで、署名リクエストのセキュリティレベルを高めたいとします。

電話認証 (2FA)

is_phone_verification_required_to_viewパラメータを渡すことで、署名者に対してドキュメントへの署名に2FAを使用するよう求めることができます。以下に例を示します。

def sign_doc_verify_phone(
client: Client,
document_id: str,
destination_folder_id: str,
signer_email: str,
signer_phone: str,
) -> SignRequest:

# Sign request params
source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE)
destination_folder = FolderMini(
id=destination_folder_id, type=FolderBaseTypeField.FOLDER
)
signer = SignRequestCreateSigner(
email=signer_email,
verification_phone_number=signer_phone,
)
# sign document
sign_request = client.sign_requests.create_sign_request(
signers=[signer],
parent_folder=destination_folder,
source_files=[source_file],
is_phone_verification_required_to_view=True,
)
return sign_request

さらに、これをmainメソッドで使用します。

def main():
...

# Sign with phone verification
sign_with_phone_verification = sign_doc_verify_phone(
client,
SIMPLE_PDF,
SIGN_DOCS_FOLDER,
SIGNER_A,
SIGNER_A_PHONE,
)
check_sign_request(sign_with_phone_verification)

署名リクエストを開こうとすると、次のように表示されます。

電話認証

パスワード認証 (2FA)

また、signerオブジェクトでpasswordパラメータを渡すことで、署名者に対してドキュメントへの署名にパスワードを使用するよう求めることもできます。以下に例を示します。

def sign_doc_verify_password(
client: Client,
document_id: str,
destination_folder_id: str,
signer_email: str,
signer_password: str,
) -> SignRequest:

# Sign request params
source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE)
destination_folder = FolderMini(
id=destination_folder_id, type=FolderBaseTypeField.FOLDER
)

# signer
signer = SignRequestCreateSigner(
email=signer_email,
password=signer_password,
)

# sign document
sign_request = client.sign_requests.create_sign_request(
signers=[signer],
parent_folder=destination_folder,
source_files=[source_file],
)

return sign_request

さらに、これをmainメソッドで使用します。

def main():
...

# Sign with phone verification
sign_with_password_verification = sign_doc_verify_password(
client,
SIMPLE_PDF,
SIGN_DOCS_FOLDER,
SIGNER_A,
"1234",
)

署名リクエストを開くと、次のように表示されます。

パスワード認証

署名者の役割

ここまでは、役割として署名者を使用してきましたが、署名プロセスをカスタマイズするために使用できる役割は他にもあります。

使用可能な役割は、署名者 (Signer)、承認者 (Approver)、最終的なコピー受信者 (Final copy reader) です。

開発者の視点から見ると、これは以下を意味します。

  • 署名者: ドキュメントにデータを追加できる人。これには、署名、イニシャル、日付の追加だけでなく、署名が含まれていなくても、テキストフィールド、チェックボックス、ラジオボタンへの入力も含まれます。
  • 承認者: この役割は、ドキュメントを承認するかどうかを尋ねられます。
  • 最終的なコピー受信者: この役割は、署名プロセスには関与しませんが、署名済みドキュメントのコピーを受け取ります。

役割を使用することにより、今回の奨学金の例ではもう少し工夫することができます。

奨学金は学部長による承認が必要であることと法務部門が契約書の最終的なコピーを受け取ることを想像してみてください。

このためのメソッドを作成します。

def sign_contract_step(
client: Client,
document_id: str,
destination_folder_id: str,
institution_email: str,
student_email: str,
dean_email: str,
legal_email: str,
) -> SignRequest:
"""Sign contract"""

# Sign request params
source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE)
destination_folder = FolderMini(
id=destination_folder_id, type=FolderBaseTypeField.FOLDER
)

# signers
institution = SignRequestCreateSigner(
email=institution_email,
role=SignRequestCreateSignerRoleField.SIGNER,
order=1,
)

student = SignRequestCreateSigner(
email=student_email,
role=SignRequestCreateSignerRoleField.SIGNER,
order=2,
)

dean = SignRequestCreateSigner(
email=dean_email,
role=SignRequestCreateSignerRoleField.APPROVER,
)

legal = SignRequestCreateSigner(
email=legal_email,
role=SignRequestCreateSignerRoleField.FINAL_COPY_READER,
)

# create sign request
sign_request = client.sign_requests.create_sign_request(
signers=[institution, student, dean, legal],
parent_folder=destination_folder,
source_files=[source_file],
is_document_preparation_needed=True,
)

return sign_request

さらに、これをmainメソッドで使用します。

def main():
...

# Multiple signers and steps
sign_contract_multi_step = sign_contract_step(
client,
CONTRACT,
SIGN_DOCS_FOLDER,
institution_email=SIGNER_A,
student_email=SIGNER_B,
dean_email=APPROVER,
legal_email=FINAL_COPY,
)
if sign_contract_multi_step.prepare_url is not None:
open_browser(sign_contract_multi_step.prepare_url)

先ほどと同様、ドキュメントを準備する必要があるため、ブラウザで準備のURLを開きます。

この例では、教育機関が左側に青で示され、学生が右側に緑で示されており、どちらも署名者であることに注目してください。

承認者にも最終的なコピー受信者にも入力データを関連付けることはできません。関連付けると、その役割は署名者に変更されます。

複数の役割の準備

署名プロセスを続行します。

  • 最初に、学部長が奨学金を承認します。
  • 次に、教育機関が奨学金に署名します。
  • 次に、学生が奨学金に署名します。
  • 最後に、法務部門が署名済みドキュメントのコピーを受け取ります。

その他の機能

このワークショップでは説明しなかった機能がいくつかあります。各自で自由に調べてみてください。

署名リクエスト

  • 複数のソースファイル — 最大10ファイルまで同時に署名できます。
  • 署名の色 — 一部の法令の要件では、署名の色が指定されています。
  • 入力による署名の無効化 — 手書きの署名の使用をユーザーに強制します。
  • 名前 — 署名リクエストにわかりやすい名前を付けます。
  • 外部ID — 署名リクエストを外部識別子にリンクします。

署名者

  • 対面 — ドキュメントの準備ができるとすぐに、選択された署名順序に関係なく、対面の署名者に対して署名を求めます。
  • 埋め込みURL — 署名するよう署名者を誘導するURL。
  • Boxログインが必要 — ユーザーにBox.comへのログインを要求します。

使用可能なSDKのメソッド

このAPIには以下のメソッドが不可欠です。

  • IDを指定して署名リクエストを取得 — IDを指定して署名リクエストオブジェクトを返します。
  • 署名リクエストのリストを取得 — ユーザーのすべての署名リクエストのリストを取得します。
  • 署名リクエストをキャンセル — IDを指定して署名リクエストをキャンセルします。

ドキュメントと参考情報

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

--

--