電子署名サービスを基幹システムやワークフローと連携させると、稟議の承認から署名依頼の送信、締結完了の受け取り、署名済PDFの保管までを人手を介さずに流せます。ただしサービスごとにAPIの単位、通知の形式、再送の条件が違い、1社の作り方をそのまま別のサービスへ当てはめた連携は、通知を取りこぼす作りになりがちです。この記事では、クラウドサインのWeb APIで署名依頼を送るcurlの手順、DocuSignとクラウドサインの状態を社内の状態へ揃える対応表、HMAC署名の有無で変わる通知の確かめ方、署名済PDFをpyHankoで検証するコマンドまでを、2026年11月時点の公式仕様に沿って説明します。
まとめ:電子署名の連携は承認ゲート・状態の正規化・証跡の3点保存で組む
最初に押さえるのは、API経由の送信がサービス側の承認機能を通らない点です。クラウドサインの仕様書は、Web APIによる送信では承認機能の送信制御が行われないと明記しています。稟議が通ったかどうかの判定は、連携する自社側のコードに置いてください。
締結完了は、ポーリングではなくWebhookで受け取ります。通知の形式と再送条件は製品ごとに違うため、受信口でいったん社内共通の状態(下書き・署名待ち・締結済み・取消・不達)へ変換し、後続の処理はその状態だけを見る作りにします。製品を追加した場合も、変更範囲は受信口のアダプタだけです。
締結後は、署名済PDF、締結証明書、通知の原文の3点を書類IDで束ねて保存します。PDFの署名が壊れていないかは、pyHankoなどの検証ツールで自社側でも確かめられます。月数十件を1社で送るだけなら、標準連携やiPaaSで対応できる規模です。
電子署名サービスと自社システムの連携を5つの処理に分けて担当範囲を決める
稟議承認から署名済PDFの格納までを5つの処理に分けた連携全体の構成
電子署名の連携は、次の5つの処理に分けると設計が進めやすくなります。番号は実行される順番です。
- 送信前の承認判定:稟議やワークフローの承認が済んだ契約だけを送信対象にする
- 署名依頼の作成と送信:書類の作成、PDFの添付、宛先の追加、送信の各APIを呼ぶ
- 状態の受信:Webhookで先方確認中・締結完了・取消などの変化を受け取る
- 締結物の取得と保存:署名済PDFと締結証明書をAPIで取得し、文書管理へ格納する
- 基幹・CRMへの書き戻し:契約マスタの状態や契約期間を更新する
1と2が送信側、3〜5が受信側です。受信側の格納と基幹同期の実装は契約書管理システムのAPI連携の実装手順で詳しく扱っているので、この記事では送信側と、製品の違いを吸収する受信口の設計に絞ります。電子署名そのものの意味や当事者型・立会人型の区別は電子署名とは何かの解説を先に読むと、以降の用語が追いやすくなります。
標準連携・iPaaS・APIの3経路から処理ごとに受け持ちを決める方法
5つの処理を全部APIで自作する必要はありません。経路ごとの向き不向きは次のとおりです。
| 経路 | 向く処理 | 限界 |
|---|---|---|
| 製品の標準連携 | CRMの画面から送信、締結PDFのストレージ保存 | 承認判定や独自の採番を挟めない |
| iPaaS | 締結完了をチャットへ通知、表計算への転記 | 再送・重複の制御が粗く、件数課金が増える |
| APIの自作 | 承認ゲート、複数製品の正規化、基幹への書き戻し | 開発と保守の費用がかかる |
判断の軸は「処理1と処理5を自社の業務ルールで制御したいか」です。承認済みの契約だけを送る、締結時に契約番号で基幹を更新する、という2点が要件に入るなら、その2つだけでもAPIで作る価値があります。通知と保存だけなら標準連携で済みます。
稟議の承認後に署名依頼を自動送信する、クラウドサインWeb APIのcurl手順
API送信は承認機能の送信制御を通らないため、承認判定を自社側に置く
クラウドサインWeb APIの仕様書(OpenAPI 0.37.2)は、書類を送信する POST /documents/{documentID} の説明に「Web API による書類送信では、承認機能による送信制御は行われません」と書いています。画面操作では上長の承認を経ないと送れない設定にしていても、APIからは素通りで送れる、という意味です。
連携側では、送信APIを呼ぶ直前に稟議の状態を読み、承認済みでなければ送らない判定を必ず入れます。判定結果と承認者IDは送信記録に残してください。監査で「誰の承認で送ったか」を問われたとき、電子署名サービス側のログだけでは答えられません。
トークン取得から書類作成・PDF添付・宛先追加・送信までを5回の呼び出しで行う
サンドボックス環境で、1通の署名依頼を送るまでの流れをcurlで示します。トークンは発行から3,600秒有効で、期限内に再要求しても新しいトークンは出ません。
# 1) アクセストークンを取得(サンドボックス)
TOKEN=$(curl -s -X POST https://api-sandbox.cloudsign.jp/token \
-d "client_id=${CLOUDSIGN_CLIENT_ID}" | jq -r .access_token)
# 2) 書類を作成(下書き)し、返ってきた id を控える
DOC_ID=$(curl -s -X POST https://api-sandbox.cloudsign.jp/documents \
-H "Authorization: Bearer ${TOKEN}" \
--data-urlencode "title=業務委託契約書(${RINGI_ID})" | jq -r .id)
# 3) 契約書PDFを添付
curl -s -X POST https://api-sandbox.cloudsign.jp/documents/${DOC_ID}/files \
-H "Authorization: Bearer ${TOKEN}" \
-F "name=contract.pdf" -F "[email protected]"
# 4) 宛先を追加(order の小さい宛先から順に確認依頼が届く)
curl -s -X POST https://api-sandbox.cloudsign.jp/documents/${DOC_ID}/participants \
-H "Authorization: Bearer ${TOKEN}" \
--data-urlencode "name=${SIGNER_NAME}" \
--data-urlencode "email=${SIGNER_EMAIL}" \
--data-urlencode "organization=${SIGNER_COMPANY}"
# 5) 送信(下書きなら送信、先方確認中ならリマインドになる)
curl -s -X POST https://api-sandbox.cloudsign.jp/documents/${DOC_ID} \
-H "Authorization: Bearer ${TOKEN}"
押さえどころは2つあります。1つは手順5が同じURLで送信とリマインドを兼ねる点で、再実行するとリマインドメールが相手に飛びます。もう1つは、宛先の送信順を直接指定するパラメータが無く、追加した順に後ろへ並ぶ点です。社内の押印者を先に、取引先を後に並べたいときは、追加の順番で制御します。既存のテンプレートから作るなら、手順2で template_id を渡します。
送信前に稟議IDと書類IDを自社DBへ記録し、再実行での二重送信を防ぐ
5回の呼び出しの途中で通信が切れると、下書きだけが残ったり、送信済みなのに自社側は未送信のままだったりします。送信処理は、稟議IDを一意キーにした送信記録テーブルを軸に組みます。
- 手順2の直後:稟議ID・書類ID・状態「作成済み」を記録する
- 手順5の直前:同じ稟議IDの状態が「送信済み」なら送信APIを呼ばない
- 手順5の成功後:状態を「送信済み」、送信日時を記録する
再実行時は記録済みの書類IDを GET /documents/{documentID} で引き、status が0(下書き)なら続きから、1(先方確認中)なら送信済みとして扱います。この確認を省くと、手順5の再実行がそのまま取引先へのリマインドになります。
製品ごとに異なる締結通知を、状態の対応表と受信アダプタで1つの形式に揃える
DocuSignとクラウドサインの状態を5つの社内状態に対応させる表
後続の処理を製品から切り離すため、受信した状態は社内共通の値に変換してから保存します。DocuSignのエンベロープ状態コードと、クラウドサインの書類状態・Webhook通知の種類を対応させると次のようになります。
| 社内状態 | DocuSign | クラウドサイン |
|---|---|---|
| 下書き | created | 書類status 0 |
| 署名待ち | sent、delivered | 書類status 1 |
| 締結済み | completed | 通知COMPLETED(status 2) |
| 取消 | declined、voided | 通知CANCELED(status 3) |
| 不達 | 該当する状態なし | 通知BOUNCED(status 1または2) |
DocuSignの signed は全員の署名直後の一時的な状態で、自動的に completed へ移るため、締結の判定には使いません。クラウドサインで注意したいのは不達の通知です。クラウドサインのWebhook仕様では、メールの不達を知らせる BOUNCED が status 1 または 2 を伴って届きます。status だけで判定すると、締結完了メールの不達(status 2)を締結完了と取り違えるので、本文の text 先頭の種類名も必ず見ます。
HMAC署名があるDocuSignと署名の無いクラウドサインの通知の確かめ方
Webhookの受信口は外部に公開されるため、偽の締結通知を受け付けない仕組みが要ります。ここは製品で作りが分かれます。
DocuSign Connectは、管理画面でHMACの鍵を作ると、本文をHMAC-SHA256でハッシュした値を X-DocuSign-Signature-1 以降のヘッダーに付けて送ってきます(ConnectのHMAC解説)。受信側は受け取ったままのバイト列で同じ計算をし、一致を確かめます。具体的なコードはDocuSign APIの実装手順に載せています。
クラウドサインのWebhookには署名がありません。代わりに仕様で送信元IPが公開されており、本番は 52.68.17.229、52.198.144.82、3.112.114.42、サンドボックスは 52.197.119.179 の各 /32 です。受信口ではこのIPからの要求だけを通し、さらに通知の documentID で GET /documents/{documentID} を呼んで、状態をAPIから取り直します。通知本文は「何かが変わった合図」として扱い、事実はAPIの応答で確定させる、という分け方です。
再送条件の違いに合わせた応答コードの返し方と、通知を正規化するPython受信コード
応答コードの扱いも製品で違います。クラウドサインは2xxを成功とし、4xxも現行仕様では成功扱いで再送しません。5xxを返したときだけ、10分間隔で最大3回再送します。一時的な障害で処理できなかった通知に4xxを返すと、その通知は二度と届きません。
以下は、2つの製品の通知を社内状態へ変換してキューに積むだけの受信口です。重い処理はキューの先のワーカーで行い、受信口は短時間で応答を返します。
import base64, hashlib, hmac, ipaddress, json, os
from flask import Flask, abort, request
app = Flask(__name__)
CLOUDSIGN_NETS = [ipaddress.ip_network(n) for n in (
"52.68.17.229/32", "52.198.144.82/32", "3.112.114.42/32")]
DS_KEY = os.environ["DS_CONNECT_HMAC_KEY"].encode()
DS_MAP = {"envelope-sent": "awaiting", "envelope-delivered": "awaiting",
"envelope-completed": "completed", "envelope-declined": "canceled",
"envelope-voided": "canceled"}
@app.post("/webhooks/cloudsign")
def cloudsign():
if not any(ipaddress.ip_address(request.remote_addr) in n for n in CLOUDSIGN_NETS):
abort(403)
body = request.get_json(force=True)
kind = body["text"].split(" :", 1)[0] # COMPLETED / CANCELED / BOUNCED
state = {"COMPLETED": "completed", "CANCELED": "canceled"}.get(kind, "bounced")
try:
enqueue("cloudsign", body["documentID"], state, body)
except Exception:
abort(503) # 5xx のときだけ再送される
return "", 200
@app.post("/webhooks/docusign")
def docusign():
raw = request.get_data()
mac = base64.b64encode(hmac.new(DS_KEY, raw, hashlib.sha256).digest()).decode()
if not hmac.compare_digest(mac, request.headers.get("X-DocuSign-Signature-1", "")):
abort(401)
event = json.loads(raw)
state = DS_MAP.get(event["event"])
if state:
enqueue("docusign", event["data"]["envelopeId"], state, event)
return "", 200
enqueue は、製品名・書類ID・社内状態の組を一意キーにして登録する関数を想定しています。同じ通知が再送されても2件目は無視されます。リバースプロキシの内側で動かす場合、remote_addr はプロキシのIPになるので、IPの制限はプロキシ側で掛けてください。冪等性と署名検証の一般論はWebhookの受信側実装の解説にまとめています。
署名済PDFと監査証跡を保存し、pyHankoで署名の改ざん有無を確かめる
署名済PDF・締結証明書・通知原文の3点を書類IDで束ねて保存する理由
締結完了を受けたら、ワーカーがAPIで締結物を取得します。クラウドサインなら書類のファイルを GET /documents/{documentID}/files/{fileID}、合意締結証明書を GET /documents/{documentID}/certificate で取れます。保存するのは次の3点です。
- 署名済PDF:電子署名とタイムスタンプが埋め込まれた原本そのもの
- 締結証明書:誰がいつ、どの認証で合意したかの記録
- 通知の原文:受信日時と送信元を含めた、締結を知った時点の証拠
署名済PDFは、取得後に一切加工しないでください。ファイル名の変更は構いませんが、透かしの追加や他のPDFとの結合をすると、署名の検証で改変ありと判定されます。契約書の電子データは電子帳簿保存法の電子取引の保存要件にも関わるため、検索に使う取引年月日・金額・取引先は契約マスタ側の項目で持たせます。要件の整理は電子契約書の保存要件の解説を参照してください。
pyHankoのvalidateコマンドで受け取ったPDFの署名を確かめる手順
保存したPDFの署名が有効かどうかは、電子署名サービスの画面を開かなくても確かめられます。PythonのPDF署名ライブラリ pyHanko は、2026年11月時点で0.38系(Python 3.10以上)です。pyHankoの検証ガイドにあるとおり、次のコマンドで署名の状態を読みやすい形で表示します。
pip install pyHanko
pyhanko sign validate --pretty-print signed.pdf
格納時にこのコマンドを流しておくと、取得の途中でファイルが壊れた場合や、誤って加工したPDFを保存した場合に気づけます。ただし、署名者の証明書を信頼できるかの判定は、どの認証局を信頼の起点にするかで結果が変わります。国内の立会人型サービスが使う証明書は既定の信頼リストに入っていないこともあるため、まずは「署名以降にPDFが改変されていないか」の確認に使うのが現実的です。ハッシュと証明書チェーンの検証の流れは電子署名の仕組みをopensslで確かめる記事で扱っています。
複数の電子署名サービスを併用するときの抽象化の判断と、自前実装を見送る条件
取引先の指定で2社以上を併用するなら送信と受信のアダプタを分けて作る
自社はクラウドサインでも、海外の取引先からDocuSignでの締結を求められる、という併用は珍しくありません。2社以上を使うと決まった時点で、連携は製品ごとのアダプタと共通部分に分けます。
共通部分に置くのは、承認ゲート、送信記録テーブル、社内状態、締結物の保存先です。アダプタには、トークンの取り方、送信の呼び出し順、通知の真正性の確かめ方、状態の変換表だけを持たせます。前の章の対応表と受信コードは、この分け方をそのまま形にしたものです。
反対に、1社しか使わない段階で抽象化の層を先に作るのは過剰です。製品ごとの差を知らないまま共通の型を決めると、2社目を入れた時点で型を作り直すことになります。2社目が決まってから、実物の差分を見て切り出すほうが短期間で済む進め方です。海外製品の制約はAdobe Acrobat SignのAPI連携の解説も参考になります。
月数十件を1社で送るだけなら標準連携で足り、API開発の目安は書き戻しの有無
自前のAPI連携を見送ってよいのは、次の条件がそろう場合です。送信が月数十件、使うサービスが1社、締結後の処理がPDFの保存とチャット通知だけ。この規模なら、製品の標準連携やiPaaSで運用でき、受信口の保守や再送の監視を抱える必要はありません。
API開発に進む目安は、締結結果を基幹やCRMへ書き戻す要件があるかどうかです。契約番号で受注や請求を自動で立ち上げたい、承認済みの契約以外は送れないようにしたい、複数のサービスの締結状況を1つの画面で見たい。このどれかに当てはまるなら、標準連携では届きません。サービス自体の選定から迷っている場合は電子契約システムの比較と選び方で判断軸を整理できます。既存の基幹やワークフローとの連携設計から相談したい場合は、API開発・システム連携の窓口で、送信件数と書き戻し先を伺ったうえで構成を提案します。
よくある質問
電子署名サービスとの連携を設計する段階で、よく確認される点をまとめました。
電子署名サービスのAPIはどの料金プランでも使えますか?
多くのサービスで、APIは上位プランか有料オプションに限られます。クラウドサインはWeb APIのオプションが無い契約で呼ぶと権限エラーが返り、DocuSignは開発用の無料環境で作り始められるものの、本番へ移すには有料の本番アカウントが必要です。開発に入る前に、本番で使う契約にAPIが含まれるかを営業窓口で確かめ、見積もりに入れておくと手戻りがありません。
社内ネットワークの制約でWebhookを受けられない場合はどうすればよいですか?
ポーリングで状態を取りに行く方式になりますが、製品ごとの上限に注意します。DocuSignはAPIの利用規則で、同じエンベロープの状態取得は15分に1回までという制限です。クラウドサインは書類ごとの last_processed_at(最終処理日時)を前回の取得時刻と比べれば、動きのあった書類だけを選び出せます。受信口だけをクラウド上に置き、社内へはキュー経由で渡す構成にすれば、Webhookを使い続けられます。
自社のWeb画面の中で署名してもらうことはできますか?
組込み署名の機能を持つサービスなら可能です。クラウドサインは宛先に電話番号を設定し、署名URLを取得するAPIで、SMS認証による組込み署名を提供しています。連携システム側の利用者IDで本人を識別する簡易認証の方式もあります。どちらもチームの設定で有効になっていることが前提なので、利用前に管理画面の設定を確認してください。DocuSignにも同様の埋め込み署名があります。
締結完了の通知が届かなかった書類はどうやって拾えばよいですか?
Webhookだけに頼らず、夜間などに照合のジョブを流す運用が必要です。送信記録テーブルで「署名待ち」のまま残っている書類IDについて、APIで現在の状態を取り直し、締結済みなら通常の格納処理へ回します。クラウドサインの差分取得の実装は契約書管理システムのAPI連携の照合ジョブの章、DocuSignの配信失敗の拾い方はDocuSign APIの実装手順にあります。
電子サインと電子署名のどちらを使っても連携の作りは同じですか?
API連携の構造はほぼ同じで、違いが出るのは署名の強さを指定する箇所です。クラウドサインでは宛先の追加時に advanced_authn_request を指定すると、高度な認証による署名が有効になる仕様です。どの契約にどの強さの署名を使うかは法務の判断なので、連携側では契約種別ごとの設定表を持ち、送信時に参照する形にしておきます。両者の証拠力の差は電子サインと電子署名の違いで解説しています。
関連記事
- 契約書管理システムのAPI連携:Webhook受信から締結PDFの冪等な格納・基幹同期までの実装手順:締結完了を受けた後の格納と基幹同期の実装
- DocuSign APIとは:JWT認証・テンプレート送信・Connectで締結完了を受け取る実装手順:DocuSign単体の認証と送信、HMAC検証のコード
- 電子署名とは?意味・仕組み・種類と法的効力をわかりやすく解説【2026年時点】:連携の前提になる電子署名の種類と法的効力
- タイムスタンプとは?仕組み・電子署名との違いと電子帳簿保存法での要否を解説【2026年時点】:署名済PDFに埋め込まれるタイムスタンプの役割
- 電子契約システムの比較と選び方とは?認証方式・連携・費用の判断軸を解説:連携のしやすさを含めたサービス選定の判断軸