
Box Sign: Create Sign Request
This item creates a signing document from the specified file on Box and sends a sign request.
Basic Configs
- Step Name
- Note
Configs for this Auto Step
- conf_OAuth2
- C1: OAuth2 Setting *
- conf_SourceFileId
- C2: Source File ID to create a signing document from *
- conf_FolderId
- C3: Folder ID to save the signing document (Root cannot be used) *
- conf_EmailAddress
- C4: Email Addresses of the signers (Write one per line) *
- conf_Password
- C5: Passwords for each signer (Write one per line)
- conf_EmailSubject
- C6: Email Subject (Default subject if blank)#{EL}
- conf_EmailMessage
- C7: Message to include in the email (Default message if blank)#{EL}
- conf_RequestId
- C8: Data item to save ID of the sign request
Notes
- Box Sign must be enabled on the Box platform (default: disabled)
- Users authenticating in the C1: OAuth2 Setting must have a Box Business plan user account
- Your Box plan limits the number of files you can ask for signatures
- See Box documentation for details
- File ID is contained in the URL: https:// {sub-domain}.app.box.com/file/(File ID)
- Folder ID is contained in the URL: https:// {sub-domain}.app.box.com/folder/(Folder ID)
- Box refresh tokens have an expiration date. Use regularly to ensure that it does not expire. (Box: Token & URL Expiration)
- If a watermarked file is subject to signature, it will result an error
Capture

See also
Script (click to open)
- An XML file that contains the code below is available to download
- box-sign-request-create.xml (C) Questetra, Inc. (MIT License)
- If you are using Professional, you can modify the contents of this file and use it as your own add-on auto step
// OAuth2 config sample at [OAuth 2.0 Setting]
// - Authorization Endpoint URL: https://account.box.com/api/oauth2/authorize
// - Token Endpoint URL: https://api.box.com/oauth2/token
// - Scope: sign_requests.readwrite root_readwrite
// - Consumer Key: (Get by Box Developer Console)
// - Consumer Secret: (Get by Box Developer Console)
main();
function main(){
//// == 工程コンフィグ・ワークフローデータの参照 / Config & Data Retrieving ==
const oauth2 = configs.get('conf_OAuth2');
const fileId = decideEditable('conf_SourceFileId', 'Source File ID');
const folderId = decideEditable('conf_FolderId', 'Folder ID');
if (folderId === '0') {
throw 'Root folder cannot be used.';
}
const signers = retrieveSigners();
const subject = configs.get('conf_EmailSubject');
const message = configs.get('conf_EmailMessage');
const requestIdDef = configs.getObject('conf_RequestId');
//// == 演算 / Calculating ==
const requestId = createRequest(oauth2, fileId, folderId, signers, subject, message);
//// == Data Updating / ワークフローデータへの代入 ==
setData(requestIdDef, requestId);
}
/**
* editable な config から設定値を読み出す
* 設定値が空の場合はエラー
* @param {String} confName 設定名
* @param {String} label エラー出力用ラベル
* @return {String} value 設定値
*/
function decideEditable(confName, label) {
let value = '';
const dataDef = configs.getObject(confName);
if (dataDef === null) {
value = configs.get(confName);
} else {
value = engine.findData(dataDef);
}
if (value === '' || value === null) {
throw `${label} is blank.`;
}
return value;
}
/**
* 署名者情報 (メールアドレスとパスワード) をデータ項目から読み出す
* 1つも設定されていない場合、上限件数を超える場合はエラー
* @return {Array<Object>} signers 署名者 {email, password} の配列
*/
function retrieveSigners() {
const emails = retrieveFilledArray('conf_EmailAddress', 'Email Address');
const passwords = retrieveFilledArray('conf_Password', 'Password');
// 件数チェック
if (emails === null || emails.length === 0) {
throw 'No Email Address.';
}
if (emails.length > 35) { // Box Sign の仕様で最大35件まで
throw 'Number of Email Addresses exceeds the limit. The maximum number is 35.';
}
// 署名者の配列を作成
const signers = emails.map(email => ({email}));
if (passwords === null) { // パスワード設定なし
return signers;
}
// パスワード設定あり
if (passwords.length !== signers.length) { // 件数が一致しない
throw 'Number of Passwords does not match the number of Email Addresses.';
}
passwords.forEach((password, i) => {
signers[i].password = password
});
return signers;
}
/**
* config から複数行のデータを読み出し、配列を生成する
* データ項目が設定されていない場合は null を返す
* データ項目が設定されていて、中身が空の場合はエラー
* 空行を含む場合はエラー (最後に空行がひとつだけある場合は無視)
* @param {String} confName config 名
* @param {String} label エラー出力に使用するラベル
* @return {Array<String>} array 空文字列を含まない配列
*/
function retrieveFilledArray(confName, label) {
const dataDef = configs.getObject(confName);
if (dataDef === null) { // データ項目が設定されていない
return null;
}
const string = engine.findData(dataDef);
if (string === null || string === '') { // データ項目の中身が空
throw `Data item for ${label} is set but its content is empty.`;
}
const array = string.split('\n');
if (array[array.length - 1] === '') { // 最後に空行があれば削除
array.pop();
}
// 空行が残っている場合はエラー
const i = array.indexOf('');
if (i !== -1) {
throw `${label} at line ${i+1} is blank.`;
}
return array;
}
/**
* Create Sign Request 署名リクエスト作成
* @param {String} oauth OAuth2 設定
* @param {String} fileId 元ファイルの ID
* @param {String} folderId 保存先フォルダの ID
* @param {Array<Object>} signers 署名者 {email, password} の配列
* @param {String} subject 送信メールの件名
* @param {String} message 送信メールに含めるメッセージ
* @return {String} requestId 署名リクエストの ID
*/
function createRequest(oauth2, fileId, folderId, signers, subject, message) {
const jsonBody = {signers};
jsonBody['source_files'] = [{
'id': fileId,
'type': 'file'
}];
jsonBody['parent_folder'] = {
'id': folderId,
'type': 'folder'
};
if (subject !== '' && subject !== null) {
jsonBody['email_subject'] = subject;
}
if (message !== '' && message !== null) {
jsonBody['email_message'] = message;
}
const url = 'https://api.box.com/2.0/sign_requests';
const response = httpClient.begin()
.authSetting(oauth2)
.body(JSON.stringify(jsonBody), 'application/json; charset=UTF-8')
.post(url);
const status = response.getStatusCode();
const responseTxt = response.getResponseAsString();
if (status !== 201) {
engine.log(responseTxt);
throw `Failed to create Sign Request. status:${status}`;
}
return JSON.parse(responseTxt).id;
}
/**
* データ項目にデータを保存する
* @param {DataDefinitionView} dataDef データ項目の DataDefinitionView
* @param {Object} value 保存する値
*/
function setData(dataDef, value) {
if (dataDef !== null) {
engine.setData(dataDef, value);
}
}