平台简介
新手指南
API协议
API文档
单点登录集成
小程序插件
公告
常见问题
开放平台使用操作手册
帮助中心 / 开放平台帮助文档 / 创建合同
创建合同
开放平台V2版本,创建合同

创建合同

1 创建合同草稿

描述:根据业务分类配置创建合同草稿,业务分类在契约锁公有云中配置。

业务分类配置介绍:

签署方:

(1)签署方预设时,用户传入的签署方与业务分类配置的签署方必须完全一致(数量、类型、顺序均匹配),此时会使用业务分类配置的签署流程、签署位置、印章等(发起方除外,发起方的签署流程下面介绍)。

(2)签署方非预设时,以参数中传入的签署方为准(发起方除外)。

发起方签署流程:

(1)发起方流程预设时,发起方使用预设的签署流程、签署位置、印章等。

(2)发起方流程非预设时,创建合同时, 需要主动传入签署动作。

文件模板:

发起合同时,必须保证合文件模板中发起方的必填参数均已填写完成。

请求地址:/v2/contract/draft

请求方法:POST

请求格式:application/json;charset=UTF-8

请求参数:

Contract(合同):

参数 类型 必须 描述
id String 合同ID(接口返回值)
bizId String 业务ID;
一个合同对应一个bizId,不能重复
tenantName String 子公司名称,若需以子公司身份发起合同需要传递该值,默认为对接方公司
subject String 合同主题(合同名称)
若业务分类中未配置文件主题按规则生成,则需要传递
description String 合同描述
sn String 合同编号;可由用户传入,
也可由契约锁自动生成
expireTime String 合同过期时间;
格式为yyyy-MM-dd HH:mm:ss,
默认过期时间为业务分类中配置的时间
ordinal Boolean 是否顺序签署;默认为true
send Boolean 是否发起合同;
发起合同后不能再进行添加文档、
添加签署方等操作
category Category 业务分类;默认为“默认业务分类”
creator User 创建人;默认为虚拟用户,
创建人必须已经加入对接方的公司
status String 合同状态(接口返回值):DRAFT(草稿)
RECALLED(已撤回),SIGNING(签署中),REJECTED(已退回),COMPLETE(已完成),EXPIRED(已过期),FILLING(拟定中),INVALIDING(作废中),INVALIDED(已作废)
signatories List<Signatory> 签署方;签署合同的公司/个人;
发起合同时必传;
templateParams List<TemplateParam> 模板参数,用于文件模板的填参(支持格式为文本、单选框、多选框格式的参数)
documents List<Document> 合同文档(接口返回值)
copySendReceivers List<CopySendReceiver> 抄送人列表
comments String 合同撤回原因(接口返回值)

Category(业务分类):

参数 类型 必须 描述
id String 业务分类ID
name String 业务分类名称;
如果id为空时,使用name来确定业务分类,
需要保证name对应的业务分类唯一

User(个人用户):

参数 类型 必须 描述
name String 名称,作为抄送接收方参数时,该参数必传(此参数仅作为合同详情接口返回值)
contact String 联系方式
contactType String 联系类型:MOBILE(手机号),EMAIL(邮箱),EMPLOYEEID(员工ID),NUMBER(员工编号)

Signatory(签署方):

参数 类型 必须 描述
id String 签署方ID(接口返回值)
tenantType String 签署方类型:COMPANY(公司),
PERSONAL(个人)
status String 签署方状态(接口返回值):DRAFT(草稿)
RECALLED(已撤回),SIGNING(签署中),REJECTED(已退回),SIGNED(已完成),EXPIRED(已过期),FILLING(拟定中),WAITING(待签署),INVALIDING(作废中),INVALIDED(已作废)
complateTime String 签署完成时间(接口返回值)
tenantName String 签署方名称
receiver User 接收人
serialNo Integer 签署顺序
actions List<Action> 签署动作(签署流程)
attachments List<Attchment> 附件要求;用于指定用户签署时上传附件
userAuthInfo UserAuthInfo 指定签署方认证信息

Action(签署动作/签署流程):

参数 类型 必须 描述
id String 签署节点ID(接口返回值)
type String 类型:COMPANY(企业签章),OPERATOR(经办人签字)
LP(法定代表人签字),AUDIT(审批)
status String 动作状态(接口返回值):INIT(初始化)
START(已启动),FINISH(已完成),STOP(意外终止)
complateTime String 签署完成时间(接口返回值)
name String 名称
serialNo Integer 执行顺序,从0开始
sealId String 印章ID;用于指定签署时所有印章
operators List<User> 操作人;用于指定公章签署人或审批人

Attchment(附件要求):

参数 类型 必须 描述
id String 附件ID(接口返回值)
title String 名称
required Boolean 是否必须;默认为false
needSign Boolean 是否需要签署;默认为false

UserAuthInfo(签署方认证信息):

参数 类型 必须 描述
idCardNo String 指定认证身份证号码
bankNo String 指定认证银行卡号,仅银行卡认证时生效
bankMobile String 指定认证银行卡手机号,仅银行卡认证时生效

CopySendReceiver(抄送人):

参数 类型 必须 描述
name String 抄送人姓名
receiver User 抄送人联系方式,联系方式类型只允许使用Mobile、Email
createTime String (接口返回值)创建时间;格式为yyyy-MM-dd HH:mm:ss
send String (接口返回值)是否已经抄送

TemplateParam(合同文档参数):

参数 类型 描述
name String 文档参数名称
value String 文档参数值
required Boolean 是否为必填参数(接口返回值)

Document(合同文档):

参数 类型 描述
id String 附件ID
title String 名称
pageCount Integer 文档页数
createTime String 创建时间;格式为yyyy-MM-dd HH:mm:ss
params List<TemplateParamBean> 合同文档参数(在获取合同详情接口中使用)

TemplateParamBean(合同文档参数,仅在获取合同详情中作为返回值):

参数 类型 描述
name String 文档参数名称
value String 文档参数值
required Boolean 是否为必填参数(接口返回值)
type ParamType 参数类型:text(文本), textarea(多行文本),date(时间), person(身份证号), radio(单选),checkbox(多选), seal(签章), signature(签名)

返回参数:

参数 类型 描述
code Integer 响应码
message String 响应消息
result Object 返回数据;格式与请求参数一致

响应码(全局响应码请查看文档末“全局响应码”):

响应码 描述
1102 DUPLICATE SIGNATORY,签署方重复
1103 ACTION REQUIRED,缺少签署节点;签署方为公司时,必须保证其下的签署流程
不为空,签署流程可以由参数传入,也可以使用业务分类中配置的签署流程。
1105 ACTION OPERATORS REQUIRED,缺少操作人;
签署方为公司时,其下的“审批”节点必须设置操作人。
1111 OPERATOR REQUIRED,缺少经办人;
存在经办人节点时,必须设置经办人。
1112 DUPLICATE BIZID,重复的bizId;
1113 SIGNATORY REQUIRED,缺少签署方
1201 SEAL NOT FOUND,找不到印章
1203 INVALID SEAL STATUS,印章不是正常状态
1301 CATEGORY CONFIG NOT MATCH,业务分类配置的签署方数量/类型
与参数中的签署方数量/类型不匹配
1302 CATEGORY CONFIG ERROR,业务分类配置数据错误;
可能原因有:业务分类中配置的操作人已离职,或其他错误。
1401 DOCUMENT REQUIRED,缺少合同文档;发起合同时必须有合同文档
1701 EMPLOYEE NOT FOUND,找不到员工
1702 EMPLOYEE DISMISSED,员工已离职
1705 EMPLOYEE NOT REGISTE,员工未注册
1116 DOCUMENT PARAM LACK,发起方未将必填参数填写完

请求示例:

Http示例

POST /v2/contract/draft HTTP/1.1
Host: [host]
x-qys-open-timestamp: [替换为请求头生成的Timestamp]
x-qys-open-signature: [替换为请求头生成的Signature]
x-qys-open-accesstoken: [替换为请求头生成的Token]
Content-Type: application/json
{
    "sn": "123321",
    "subject": "V2合同",
    "description": "合同描述",
    "expireTime": "2019-08-25 00:00:00",
    "ordinal": true,
    "send": false,
    "category": {
        "name": "V2"
    },
    "creator": {
        "contact": "18435186216",
        "contactType": "MOBILE"
    },
    "signatories": [
        {
            "tenantType": "COMPANY",
            "tenantName": "思晨教育",
            "receiver": {
                "contact": "10100000000",
                "contactType": "MOBILE"
            },
            "serialNo": 1,
            "actions": [
                {
                    "type": "COMPANY",
                    "name": "公章签署动作",
                    "serialNo": 1,
                    "operators": [
                        {
                            "contact": "10100000000",
                            "contactType": "MOBILE"
                        }
                    ]
                },
                {
                    "type": "AUDIT",
                    "name": "审批动作",
                    "serialNo": 3,
                    "operators": [
                        {
                            "contact": "10100000000",
                            "contactType": "MOBILE"
                        }
                    ]
                },
                {
                    "type": "LP",
                    "name": "法人签署动作",
                    "serialNo": 4
                }
            ]
        },
        {
            "tenantType": "PERSONAL",
            "tenantName": "吉哲",
            "receiver": {
                "contact": "10100000000",
                "contactType": "MOBILE"
            },
            "serialNo": 2
        }
    ]
}
Java示例

// 初始化sdkClient
String serverUrl = "https://openapi.qiyuesuo.cn";
String accessKey = "替换为您申请的开放平台App Token";
String accessSecret = "替换为您申请的开放平台App Secret";
SdkClient sdkClient = new SdkClient(serverUrl, accessKey, accessSecret);
// 合同基本参数
Contract contract = new Contract();
contract.setSubject("测试合同");
contract.setCategory(new Category("个人-平台-预设签署方-默认流程"));
contract.setBizId("");
contract.setSend(false);
// 个人
Signatory signatory1 = new Signatory();
signatory1.setTenantName("个人接收方姓名");
signatory1.setTenantType("PERSONAL");
signatory1.setReceiver(new User("个人接收方姓名", "10100000000", "MOBILE"));
signatory1.setSerialNo(1);
// 对接方
Signatory signatory2 = new Signatory();
signatory2.setTenantName("测试合同");
signatory2.setTenantType("COMPANY");
signatory2.setReceiver(new User("公司接收方名称", "10100000000", "MOBILE"));
signatory2.setSerialNo(2);
Action action = new Action("COMPANY", 1);
signatory2.addAction(action);
// 设置签署方
contract.addSignatory(signatory1);
contract.addSignatory(signatory2);
contract.addTemplateParam(new TemplateParam("param1", "value1"));
contract.addTemplateParam(new TemplateParam("param2", "value2"));
// 创建合同
ContractDraftRequest request = new ContractDraftRequest(contract);
String response = sdkClient.service(request);
SdkResponse<Contract> responseObj = JSONUtils.toQysResponse(response, Contract.class);
// 返回结果
if(responseObj.getCode() == 0) {
    Contract result = responseObj.getResult();
    logger.info("创建合同成功,合同ID:{}", result.getId());
} else {
    logger.info("请求失败,错误码:{},错误信息:{}", responseObj.getCode(), responseObj.getMessage());
}
C#示例

//初始化sdkClient
String serverUrl = "https://openapi.qiyuesuo.cn";
String accessKey = "替换为您申请的开放平台App Token";
String accessSecret = "替换为您申请的开放平台App Secret";
SDKClient client = new SDKClient(accessKey, accessSecret, serverUrl);
ContractDraftRequest request = new ContractDraftRequest();
Contract contract = new Contract();
contract.Subject = "测试合同";
//添加对接方签署方
Signatory platformSignatory = new Signatory("COMPANY", new User("对接方经办人姓名", "101000000000", "MOBILE"), 1);
platformSignatory.TenantName = "测试公司";//对接方公司名称
//添加对接方签署流程,可根据需要调整
//目前对接方签署流程为:(1)员工审批 (2)法人章签署(3)公章签署
// 审批流程,并设置审批操作人
SignAction aduitAction = new SignAction("AUDIT", 1);
aduitAction.AddOperators(new User("101000000000", "MOBILE"));
platformSignatory.AddAction(aduitAction);
// 公章签署流程,并设置签署公章ID
SignAction sealAction = new SignAction("COMPANY", 2);
sealAction.SealId = "2490828768980361630";
platformSignatory.AddAction(sealAction);
// 法人章签署流程
platformSignatory.AddAction(new SignAction("LP", 3));
contract.AddSignatory(platformSignatory);
//添加个人签署方,并设置个人签署方需要上传的附件内容
Signatory personalSignatory = new Signatory("PERSONAL", new User("个人接收方姓名", "101000000000", "MOBILE"), 2);
personalSignatory.TenantName = "个人接收方姓名";//接收方名称
personalSignatory.AddAttachment(new Attachment("附件", true, false));//添加上传附件要求,并设置为必须上传
contract.AddSignatory(personalSignatory);
//设置合同基本信息
contract.ExpireTime = "2019-07-28 23:59:59";//设置合同过期时间,合同过期时间需要晚于发起时间
contract.Send = false;  //合同不发起
request.Contract = contract;
string response = null;
try
{
    response = client.Service(request);
}
catch (Exception e)
{
    throw new Exception("创建合同草稿请求服务器失败,失败原因" + e.Message);
}
SdkResponse<Contract> sdkResponse = HttpJsonConvert.DeserializeResponse<Contract>(response);
if (!sdkResponse.Code.Equals(0))
{
    throw new Exception("创建合同草稿失败,失败原因:" + sdkResponse.Message);
}
Console.WriteLine("合同草稿创建成功");
PHP示例

// 初始化$sdkClient
class Util {
    const     url = "https://openapi.qiyuesuo.cn";
    const     accessKey = "替换为您申请的开放平台App Token";
    const     accessSecret = "替换为您申请的开放平台App Secret";
}
$sdkClient = Util::getSDk();
/\*\* 合同基本信息 \*\*/
$contract = new Contract();
//        $contract->setId("");
$contract->setBizId("1111111");
$contract->setSubject("合同名称");
$contract->setDescription("合同描述");
$contract->setSn("123321");
$contract->setExpireTime("2019-07-25 00:00:00");
$contract->setOrdinal(true);
$contract->setSend(false);
/\*\*指定业务分类\*\*/
$category = new Category();
$category->setName("业务分类名称");
$contract->setCategory($category);
$creator = new User();
$creator->setContact("10100000000");
$creator->setContactType("MOBILE");
$contract->setCreator($creator);
/\*\*公司签署方\*\*/
$companySignatory = new Signatory();
$companySignatory->setTenantType("COMPANY");
$companySignatory->setTenantName("测试企业");
$companySignatory->setSerialNo(1);
/\*\*公司签署方接收人\*\*/
$receiver = new User();
$receiver->setContact("10100000000");
$receiver->setContactType("MOBILE");
$companySignatory->setReceiver($receiver);
/\*\*公章签署动作\*\*/
$companyAction = new Action();
$companyAction->setType("COMPANY");
$companyAction->setName("公章签署动作");
$companyAction->setSerialNo(1);
/\*\*公章签署操作人\*\*/
$companyOperator = new User();
$companyOperator->setContact("10100000000");
$companyOperator->setContactType("MOBILE");
$companyOperators = array();
array_push($companyOperators, $companyOperator);
$companyAction->setOperators($companyOperators);
/\*\*经办人签字动作\*\*/
$operatorAction = new Action();
$operatorAction->setType("OPERATOR");
$operatorAction->setName("经办人签字动作");
$operatorAction->setSerialNo(2);
/\*\*经办人签字操作人\*\*/
$operatorOperator = new User();
$operatorOperator->setContact("10100000000");
$operatorOperator->setContactType("MOBILE");
$operatorOperators = array();
array_push($operatorOperators, $operatorOperator);
$operatorAction->setOperators($operatorOperators);
/\*\*审批动作\*\*/
$auditAction = new Action();
$auditAction->setType("AUDIT");
$auditAction->setName("审批动作");
$auditAction->setSerialNo(3);
/\*\*审批操作人\*\*/
$auditOperator = new User();
$auditOperator->setContact("10100000000");
$auditOperator->setContactType("MOBILE");
$auditOperators = array();
array_push($auditOperators, $auditOperator);
$auditAction->setOperators($auditOperators);
/\*\*法人签署动作\*\*/
$lpAction = new Action();
$lpAction->setType("LP");
$lpAction->setName("法人签署动作");
$lpAction->setSerialNo(4);
$actions = array();
/\*\*公司签署方设置公章签署动作\*\*/
array_push($actions, $companyAction);
/\*\*公司签署方设置经办人签字动作\*\*/
array_push($actions, $operatorAction);
/\*\*公司签署方设置审批动作\*\*/
array_push($actions, $auditAction);
/\*\*公司签署方设置审批动作\*\*/
array_push($actions, $lpAction);
$companySignatory->setActions($actions);
/\*\*个人签署方\*\*/
$personalSignatory = new Signatory();
$personalSignatory->setTenantType("PERSONAL");
$personalSignatory->setTenantName("个人签署方名称");
$personalSignatory->setSerialNo(2);
$receiver = new User();
$receiver->setContact("10100000000");
$receiver->setContactType("MOBILE");
$personalSignatory->setReceiver($receiver);
/\*\*所有签署方\*\*/
$signatories = array();
array_push($signatories, $companySignatory);
array_push($signatories, $personalSignatory);
/\*\*填写模板参数\*\*/
$templateParam1 = new TemplateParam();
$templateParam1->setName("参数1");
$templateParam1->setValue("值1");
$templateParams = array();
array_push($templateParams, $templateParam1);
/\*\*合同文档\*\*/
$document1 = new Document();
$document1->setId("2589678690921123947");
$documents = array();
array_push($documents, $document1);
/\*\*合同签署方、文档、文档参数\*\*/
$contract->setSignatories($signatories);
$contract->setTemplateParams($templateParams);
$contract->setDocuments($documents);
$baseRequest = new ContractDraftRequest($contract);
$result = $sdkClient->service($baseRequest);
print_r($result);
Python示例

# 初始化sdkClient
url = "https://openapi.qiyuesuo.cn"
accessToken = '替换为您申请的开放平台App Token'
accessSecret = '替换为您申请的开放平台App Secret'
sdkClient = SdkClient(url, accessToken, accessSecret)
draft_contract = Contract()
draft_contract.set_subject("合同主题-人事合同")
# 设置签署方 - 对接方公司,tenantName更换为您公司的名称,接收方更正为您公司员工
company_signatory = Signatory()
company_signatory.set_tenantType("COMPANY")
company_signatory.set_tenantName("测试公司")
company_signatory.set_serialNo(1)
company_receiver = User()
company_receiver.set_contact("10100000000")
company_receiver.set_contactType("MOBILE")
company_signatory.set_receiver(company_receiver)
# 设置对接方公司签署流程 - 审批流程,并设置审批人
audit_action = Action()
audit_action.set_type("AUDIT")
audit_action.set_serialNo(1)
audit_operator = User()
audit_operator.set_contact("10100000000")
audit_operator.set_contactType("MOBILE")
audit_action.set_operators([audit_operator])
# 设置对接方公司签署流程 - 公章签署流程,并设置该流程应该签署的公章
seal_action = Action()
seal_action.set_type("COMPANY")
seal_action.set_serialNo(2)
seal_action.set_sealId("2490828768980361630")
# 设置对接方公司签署流程 - 法人章签署流程
lp_action = Action()
lp_action.set_type("LP")
lp_action.set_serialNo(3)
company_signatory.set_actions([audit_action, seal_action, lp_action])
# 设置签署方 - 个人签署方,并设置附件上传要求
personal_signatory = Signatory()
personal_signatory.set_tenantType("PERSONAL")
personal_signatory.set_serialNo(2)
personal_signatory.set_tenantName("个人接收方姓名")
personal_receiver = User()
personal_receiver.set_contact("10100000000")
personal_receiver.set_contactType("MOBILE")
personal_signatory.set_receiver(personal_receiver)
# 生成上传附件要求
personal_attachment = Attachment()
personal_attachment.set_title("附件-身份证正面照")
personal_attachment.set_required(True)
personal_signatory.set_attachments([personal_attachment])
draft_contract.set_signatories([company_signatory, personal_signatory])
# 设置合同过期时间
draft_contract.set_expireTime("2019-07-28 23:59:59")
# 不发起合同
draft_contract.set_send(False)
# 请求服务器
draft_response = sdkClient.request(ContractDraftRequest(draft_contract))
# 解析返回数据
draft_mapper = json.loads(draft_response)
if draft_mapper['code'] != 0:
    raise Exception("创建合同草稿失败,失败原因:", draft_mapper['message'])
draft_result = draft_mapper['result']
draft_contractid = draft_result['id']
print('创建合同草稿成功,合同ID:', draft_contractid)

2 添加合同文档

2.1 用文件添加合同文档

请求地址:/v2/document/addbyfile

请求方法:POST

请求格式: multipart/form-data;charset=UTF-8

请求参数:

参数 类型 必须 描述
contractId String 合同ID,合同ID与业务ID二选一,不能同时为空
bizId String 业务ID,合同ID与业务ID二选一,不能同时为空
tenantName String 子公司名称,若使用业务ID添加合同文件,且合同是以子公司身份创建的,则需要传递该值,用于确定合同主体
title String 名称
file File 合同文件
fileSuffix String 文件类型(文件后缀):
doc,docx,pdf,jpeg,png,jpg,gif,tiff,html,htm
documentSort Integer 文档指定排序

返回参数:

参数 类型 描述
code Integer 响应码
message String 响应消息
result Response 返回数据

Response(返回数据):

参数 类型 描述
documentId String 合同文档ID

响应码(全局响应码请查看文档末“全局响应码”):

响应码 描述
1101 INVALID CONTRACT STATUS,合同状态无效;
只能为“草稿”状态合同添加文档。
1403 INVALID FILE,无效的合同文件;
合同文件转换失败,可能是由于文件损坏或者文件类型错误。

请求示例:

Http示例

POST /v2/document/addbyfile HTTP/1.1
Host: [host]
x-qys-open-timestamp: [替换为请求头生成的Timestamp]
x-qys-open-signature: [替换为请求头生成的Signature]
x-qys-open-accesstoken: [替换为请求头生成的Token]
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="contractId"
2591540368898105360
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Content-Disposition: form-data; name="title"
文件文档
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Content-Disposition: form-data; name="file"; filename="/C:/Users/QYS/Desktop/Test/授权.pdf
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Content-Disposition: form-data; name="fileSuffix"
pdf
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Java示例

// 初始化sdkClient
String serverUrl = "https://openapi.qiyuesuo.cn";
String accessKey = "替换为您申请的开放平台App Token";
String accessSecret = "替换为您申请的开放平台App Secret";
SdkClient sdkClient = new SdkClient(serverUrl, accessKey, accessSecret);
// 添加合同文档
DocumentAddByFileRequest request = new DocumentAddByFileRequest(contractId,
                new StreamFile(new FileInputStream("E:/test/NoSign.pdf")), "pdf", "文件一");
String response = sdkClient.service(request);
SdkResponse<DocumentAddResult> responseObj = JSONUtils.toQysResponse(response, DocumentAddResult.class);
if(responseObj.getCode() == 0) {
    DocumentAddResult result = responseObj.getResult();
    logger.info("添加合同文档成功,文档ID:{}", result.getDocumentId());
} else {
    logger.info("请求失败,错误码:{},错误信息:{}", responseObj.getCode(), responseObj.getMessage());
}
C#示例

//初始化sdkClient
string serverUrl = "https://openapi.qiyuesuo.cn";
string accessKey = "替换为您申请的开放平台App Token";
string accessSecret = "替换为您申请的开放平台App Secret";
SDKClient client = new SDKClient(serverUrl, accessKey, accessSecret);
string contractId = "2589012016299597907";
// 引入待添加文件
string path = "C:\\Users\\Richard Cheung\\Documents\\契约锁\\测试\\人事合同.pdf";
Stream file = new FileStream(path, FileMode.Open);
// 组装根据文件添加文档请求
DocumentAddByFileRequest request = new DocumentAddByFileRequest(contractId, "添加文件", file, "pdf");
string response = null;
try
{
    response = client.Service(request);
}
catch (Exception e)
{
    throw new Exception(e.Message);
}
// 解析返回结果
SdkResponse<DocumentAddResult> responseObject = HttpJsonConvert.DeserializeResponse<DocumentAddResult>(response);
Console.WriteLine(HttpJsonConvert.SerializeObject(responseObject));
PHP示例

// 初始化$sdkClient
class Util {
    const     url = "https://openapi.qiyuesuo.cn";
    const     accessKey = "替换为您申请的开放平台App Token";
    const     accessSecret = "替换为您申请的开放平台App Secret";
}
$sdkClient = Util::getSDk();
$documentAddByFileRequest = new DocumentAddByFileRequest();
$documentAddByFileRequest->setContractId('2590758386643734529');
$documentAddByFileRequest->setBizId("1111111");
$file_path = "C:/Users/QYS/Desktop/Test/444.pdf";
$file_path = iconv("UTF-8", "GBK", realpath($file_path));
$file = new \CURLFile($file_path);
$documentAddByFileRequest->setFile($file);
$documentAddByFileRequest->setFileSuffix('pdf');
$documentAddByFileRequest->setTitle('V2添加文档');
$result = $sdkClient->service($documentAddByFileRequest);
print_r($result);
return $result;
Python示例

#初始化SdkClient
url = "https://openapi.qiyuesuo.cn"
accessToken = '替换为您申请的开放平台App Token'
accessSecret = '替换为您申请的开放平台App Secret'
sdkClient = SdkClient(url, accessToken, accessSecret)
documentbyfile_request = DocumentAddByFileRequest()
file = open("C:\\Users\\Richard Cheung\\Documents\\契约锁\\测试\\测试合同.pdf", "rb")
documentbyfile_request.set_file(file)
documentbyfile_request.set_contractId(draft_contractid)
# 将fileSuffix替换为将上传文件正确的文件类型
documentbyfile_request.set_fileSuffix('pdf')
documentbyfile_request.set_title('本地文件上传文档')
# 请求服务器
documentbyfile_response = sdkClient.request(documentbyfile_request)
# 解析返回数据
documentbyfile_mapper = json.loads(documentbyfile_response)
if documentbyfile_mapper['code'] != 0:
    raise Exception('根据本地文件添加合同文档失败,失败原因:', documentbyfile_mapper['message'])
documentbyfile_result = documentbyfile_mapper['result']
file_documentId = documentbyfile_result['documentId']
print('根据本地文件添加合同文档成功,文档ID:', file_documentId)

2. 2 用模板添加合同文档

请求地址:/v2/document/addbytemplate

请求方法:POST

请求格式:application/json;charset=UTF-8

请求参数:

参数 类型 必须 描述
contractId String 合同ID,合同ID与业务ID二选一,不能同时为空
bizId String 业务ID,合同ID与业务ID二选一,不能同时为空
tenantName String 子公司名称,若使用业务ID添加合同文件,且合同是以子公司身份创建的,则需要传递该值,用于确定合同主体
title String 名称
templateId String 模板ID
templateParams List<TemplateParam> 模板参数;如果是参数模板,则必填(支持格式为文本、单选框、多选框格式的参数)
documentSort Integer 文档指定排序

TemplateParam(模板参数):

参数 类型 必须 描述
name String 参数名称
value String 参数值

返回参数:

参数 类型 描述
code Integer 响应码
message String 响应消息
result Response 返回数据

Response(返回数据):

参数 类型 描述
documentId String 合同文档ID

请求示例:

Http示例

POST /v2/document/addbytemplate HTTP/1.1
Host: [host]
x-qys-open-timestamp: [替换为请求头生成的Timestamp]
x-qys-open-signature: [替换为请求头生成的Signature]
x-qys-open-accesstoken: [替换为请求头生成的Token]
Content-Type: application/json

{ "contractId": "2593815518218461185", "bizId": null, "title": "V2添加模板文档", "templateId": "2560778409594396776", "templateParams": [ { "name": "乙方姓名", "value": "张三" } ] }

Java示例

// 初始化sdkClient
String serverUrl = "https://openapi.qiyuesuo.cn";
String accessKey = "替换为您申请的开放平台App Token";
String accessSecret = "替换为您申请的开放平台App Secret";
SdkClient sdkClient = new SdkClient(serverUrl, accessKey, accessSecret);
// 添加合同文档
List<TemplateParam> params = new ArrayList<>();
params.add(new TemplateParam("param1", "val1"));
params.add(new TemplateParam("param2", "val2"));
DocumentAddByTemplateRequest request = new DocumentAddByTemplateRequest(contractId,
        templateId, params, "文件二");
String response = sdkClient.service(request);
SdkResponse<DocumentAddResult> responseObj = JSONUtils.toQysResponse(response, DocumentAddResult.class);
if(responseObj.getCode() == 0) {
    DocumentAddResult result = responseObj.getResult();
    logger.info("添加合同文档成功,文档ID:{}", result.getDocumentId());
} else {
    logger.info("请求失败,错误码:{},错误信息:{}", responseObj.getCode(), responseObj.getMessage());
}
C#示例

string serverUrl = "https://openapi.qiyuesuo.cn";
string accessKey = "替换为您申请的开放平台App Token";
string accessSecret = "替换为您申请的开放平台App Secret";
SDKClient client = new SDKClient(accessKey, accessSecret, serverUrl);
string contractId = "2589012016299597907";
string templateId = "2562841550577214123";
// 组装根据模板创建文档请求
DocumentAddByTemplateRequest request = new DocumentAddByTemplateRequest(contractId, "添加模板", templateId);
// 设置模板参数内容
request.AddTemplateParam(new TemplateParam("Sender", "契约锁"));
request.AddTemplateParam(new TemplateParam("Reciver1", "开放平台"));
request.AddTemplateParam(new TemplateParam("Reciver2", "对接方公司"));
string response = null;
try
{
    response = client.Service(request);
}
catch (Exception e)
{
    throw new Exception(e.Message);
}
// 解析返回内容
SdkResponse<DocumentAddResult> responseObject = HttpJsonConvert.DeserializeResponse<DocumentAddResult>(response);
Console.WriteLine(HttpJsonConvert.SerializeObject(responseObject));
PHP示例

// 初始化$sdkClient
class Util {
    const     url = "https://openapi.qiyuesuo.cn";
    const     accessKey = "替换为您申请的开放平台App Token";
    const     accessSecret = "替换为您申请的开放平台App Secret";
}
$sdkClient = Util::getSDk();
$documentAddByTemplateRequest = new DocumentAddByTemplateRequest();
$documentAddByTemplateRequest->setContractId('2590758386643734529');
$documentAddByTemplateRequest->setBizId("1111111");
$documentAddByTemplateRequest->setTitle('V2添加模板文档');
$documentAddByTemplateRequest->setTemplateId('2558597440364655396');
/\*\*填写模板参数\*\*/
$templateParam1 = new TemplateParam();
$templateParam1->setName("乙方姓名");
$templateParam1->setValue("张三");
$templateParams = array();
array_push($templateParams, $templateParam1);
$documentAddByTemplateRequest->setTemplateParams($templateParams);
$result = $sdkClient->service($documentAddByTemplateRequest);
print_r($result);
return $result;
Python示例

#初始化SdkClient
url = "https://openapi.qiyuesuo.cn"
accessToken = '替换为您申请的开放平台App Token'
accessSecret = '替换为您申请的开放平台App Secret'
sdkClient = SdkClient(url, accessToken, accessSecret)
documentbytemplate_request = DocumentAddByTemplateRequest()
documentbytemplate_request.set_title('模板上传文档')
documentbytemplate_request.set_contractId(draft_contractid)
documentbytemplate_request.set_templateId('2492236993899110515')
# 若模板为参数模板,设置模板中的参数值
documentbytemplate_request.set_templateParams(
    [TemplateParam('接收方1', '契约锁'), TemplateParam('接收方2', '电子合同')])
# 请求服务器
documentbytemplate_response = sdkClient.request(documentbytemplate_request)
# 解析返回数据
documentbytemplate_mapper = json.loads(documentbytemplate_response)
if documentbytemplate_mapper['code'] != 0:
    raise Exception('根据模板添加合同文档失败,失败原因:', documentbytemplate_mapper['message'])
documentbytemplate_result = documentbytemplate_mapper['result']
template_documentId = documentbytemplate_result['documentId']
print('根据模板添加合同文档成功,文档ID:', template_documentId)

3 发起合同

描述:调用此接口来发起“草稿”状态的合同。合同发起后,签署方将收到签署通知签署合同。支持在发起合同时指定签署位置。

请求地址:/v2/contract/send

请求方法:POST

请求格式:application/json;charset=UTF-8

请求参数:

参数 类型 必须 描述
contractId String 合同ID,合同ID与业务ID二选一,不能同时为空
bizId String 业务ID,合同ID与业务ID二选一,不能同时为空
tenantName String 子公司名称,若使用业务ID发起合同,且合同是以子公司身份创建的,则需要传递该值,用于确定合同主体
stampers List 指定签署位置

Stamper(签署位置):

参数 类型 必须 描述
actionId String 签署节点ID;公司的签署位置必须(创建合同草稿接口返回值)
signatoryId String 签署方ID;个人的签署位置必传(创建合同草稿接口返回值)
type String 签署类型:
COMPANY(公章),PERSONAL(个人签名),
LP(法人章),TIMESTAMP(时间戳),ACROSS_PAGE(骑缝章)
documentId String 合同文档ID
keyword String 关键字
keywordIndex Integer 关键字索引:1代表第1个关键字,0代码所有关键字
,-1代表倒数第1个关键字;默认为1
page Integer 坐标页码,0代表所有
offsetX Decimal 横坐标/关键字偏移量
offsetY Decimal 纵坐标/关键字偏移量

签署位置说明:

签署位置有以下两种表现方式:

1、用关键字确定坐标:
keyword:关键字。
offsetX:横坐标偏移量;默认合同页的宽为1,所以取值范围是(-1, 1)。
offsetY:纵坐标偏移量;默认合同页的高为1,所有取值范围是(-1, 1)。
找到keyword的坐标(x, y),再加上偏移量(offsetX, offsetY),最终得到的坐标是(x+offsetX, y+offsetY)。
坐标原点是合同页的左下角,坐标是指印章图片的左下角的坐标。

2、直接确定坐标:
page:印章所在页码;从1开始。
offsetX:横坐标;默认合同页的宽为1,所以取值范围是(0, 1)。
offsetY:纵坐标;默认合同页的高为1,所以取值范围是(0, 1)。
由page确定页码,由(offsetX, offsetY)确定坐标。
坐标原点是合同页的左下角,坐标是指印章图片的左下角的坐标。

返回参数:

参数 类型 描述
code Integer 响应码
message String 响应消息

响应码(全局响应码请查看文档末“全局响应码”):

响应码 描述
1101 INVALID CONTRACT STATUS,合同状态无效;
只能发起“草稿”状态合同。
1108 KEYWORD NOT FOUND,未找到关键字;
签署位置中关键字未在文档中找到。
1109 SIGN PAGE BEYOND,签署页码超出文档页数;
签署位置中的页码超出文档页数。
1203 INVALID SEAL STATUS,无效的印章状态
1116 DOCUMENT PARAM LACK,发起方未将必填参数填写完

请求示例:

Http示例

POST /v2/contract/send HTTP/1.1
Host: [host]
x-qys-open-timestamp: [替换为请求头生成的Timestamp]
x-qys-open-signature: [替换为请求头生成的Signature]
x-qys-open-accesstoken: [替换为请求头生成的Token]
Content-Type: application/json
{
    "contractId": "2591540368898105360",
    "bizId": null,
    "stampers": [{
        "actionId": "2591541618892972178",
        "type": "COMPANY",
        "documentId": "2591542337725374704",
        "sealId": "2566229349702860958",
        "offsetX": "0.1",
        "offsetY": "-0.1",
        "keyword": "劳动",
        "keywordIndex": "2"
    }, {
        "actionId": "2591541618892972178",
        "type": "COMPANY",
        "documentId": "2591542337725374704",
        "sealId": "2566229349702860958",
        "offsetX": "0.5",
        "offsetY": "0.5",
        "page": "1"
    }, {
        "signatoryId": "2591541619077521559",
        "type": "PERSONAL",
        "documentId": "2591542337725374704",
        "offsetX": 0.9,
        "offsetY": 0.9,
        "page": 1
    }]
}
Java示例

// 初始化sdkClient
String serverUrl = "https://openapi.qiyuesuo.cn";
String accessKey = "替换为您申请的开放平台App Token";
String accessSecret = "替换为您申请的开放平台App Secret";
SdkClient sdkClient = new SdkClient(serverUrl, accessKey, accessSecret);
// 发起时可以设置签署位置
Stamper stamper = new Stamper();
stamper.setActionId(2589310177048080947L);
stamper.setDocumentId(2589310172379820580L);
stamper.setType("COMPANY");
stamper.setPage(1);
stamper.setOffsetX(0.1);
stamper.setOffsetY(0.1);
Stamper stamper2 = new Stamper();
stamper2.setActionId(2589310177048080947L);
stamper2.setDocumentId(2589310172379820580L);
stamper2.setType("COMPANY");
stamper2.setPage(1);
stamper2.setOffsetX(0.2);
stamper2.setOffsetY(0.1);
List<Stamper> stampers = new ArrayList<>();
stampers.add(stamper);
stampers.add(stamper2);
// 发起合同
ContractSendRequest request = new ContractSendRequest(2589310172899914283L, stampers);
String response = sdkClient.service(request);
SdkResponse<Object> responseObj = JSONUtils.toQysResponse(response);
if(responseObj.getCode() == 0) {
    logger.info("合同发起成功");
} else {
    logger.info("请求失败,错误码:{},错误信息:{}", responseObj.getCode(), responseObj.getMessage());
}
C#示例

string serverUrl = "https://openapi.qiyuesuo.cn";
string accessKey = "替换为您申请的开放平台App Token";
string accessSecret = "替换为您申请的开放平台App Secret";
SDKClient client = new SDKClient(accessKey, accessSecret, serverUrl);
ContractSendRequest request = new ContractSendRequest();
//指定签署位置 
//发起方(公司):印章签署位置、法人章签署位置、时间戳位置
Stamper sealStamper = new Stamper();
sealStamper.DocumentId = documentId1;
sealStamper.ActionId = companyActionId;
sealStamper.Type = "COMPANY";
// 绝对位置定位:页数、X、Y定位
sealStamper.Page = 1;
sealStamper.OffsetX = 0.1;
sealStamper.OffsetY = 0.2;
// 关键字位置定位:keyword,keywordIndex,X,Y
//sealStamper.Keyword = "甲方签字"; //确保文件中包含该关键字
//sealStamper.KeywordIndex = 1;
//sealStamper.OffsetX = 0.0;
//sealStamper.OffsetY = 0.0;
Stamper lpStamper = new Stamper();
lpStamper.DocumentId = documentId1;
lpStamper.ActionId = lpActionId;
lpStamper.Type = "LP";
lpStamper.Page = 1;
lpStamper.OffsetX = 0.4;
lpStamper.OffsetY = 0.6;
Stamper timeStamper = new Stamper();
timeStamper.DocumentId = documentId1;
timeStamper.ActionId = companyActionId;
timeStamper.Type = "TIMESTAMP";
timeStamper.Page = 1;
timeStamper.OffsetX = 0.3;
timeStamper.OffsetY = 0.5;
//个人签署方 签署位置
Stamper personalStamper = new Stamper();
personalStamper.DocumentId = documentId1;
personalStamper.SignatoryId = personalSignatoryId;
personalStamper.Type = "PERSONAL";
personalStamper.Page = 1;
personalStamper.OffsetX = 0.7;
personalStamper.OffsetY = 0.5;
request.AddStamper(sealStamper);
request.AddStamper(lpStamper);
request.AddStamper(timeStamper);
request.AddStamper(personalStamper);
string response = null;
try
{
    response = client.Service(request);
}
catch (Exception e)
{
    throw new Exception("发起合同请求服务器失败,失败原因:" + e.Message);
}
SdkResponse<Object> sdkResponse = HttpJsonConvert.DeserializeResponse<Object>(response);
if (!sdkResponse.Code.Equals(0))
{
    throw new Exception("发起合同失败,失败原因:" + sdkResponse.Message);
}
Console.WriteLine("合同发起成功");
PHP示例

// 初始化$sdkClient
class Util {
    const     url = "https://openapi.qiyuesuo.cn";
    const     accessKey = "替换为您申请的开放平台App Token";
    const     accessSecret = "替换为您申请的开放平台App Secret";
}
$sdkClient = Util::getSDk();
$contractSendRequest = new ContractSendRequest();
$contractSendRequest->setContractId('2590758386643734529');
$contractSendRequest->setBizId("1111111");
/\*\*个指定签署位置:关键字定位\*\*/
$stamper1 = new Stamper();
$stamper1->setType('COMPANY');
$stamper1->setActionId('2590758390800289796');
$stamper1->setDocumentId('2590764888637018192');
$stamper1->setSealId('2555244623418466517');
$stamper1->setKeyword('劳动');
$stamper1->setKeywordIndex('2');
$stamper1->setOffsetX('0.1');
$stamper1->setOffsetY('-0.1');
/\*\*个指定签署位置:坐标定位\*\*/
$stamper2 = new Stamper();
$stamper2->setType('COMPANY');
$stamper2->setActionId('2590758390800289796');
$stamper2->setDocumentId('2590762507098624044');
$stamper2->setSealId('2555244623418466517');
$stamper2->setPage('1');
$stamper2->setOffsetX('0.5');
$stamper2->setOffsetY('0.5');
$stampers = array();
array_push($stampers, $stamper1);
array_push($stampers, $stamper2);
$contractSendRequest->setStampers($stampers);
$result = $sdkClient->service($contractSendRequest);
print_r($result);
return $result;
Python示例

#初始化SdkClient
url = "https://openapi.qiyuesuo.cn"
accessToken = '替换为您申请的开放平台App Token'
accessSecret = '替换为您申请的开放平台App Secret'
sdkClient = SdkClient(url, accessToken, accessSecret)
# 设置签署位置 - 公章签署
seal_stamper = Stamper()
seal_stamper.set_actionId(company_actionId)
seal_stamper.set_documentId(file_documentId)
seal_stamper.set_type('COMPANY')
seal_stamper.set_offsetX(0.3)
seal_stamper.set_offsetY(0.5)
seal_stamper.set_page(1)
# 设置签署位置 - 法人章签署
lp_stamper = Stamper()
lp_stamper.set_actionId(lp_actionId)
lp_stamper.set_documentId(file_documentId)
lp_stamper.set_type('LP')
lp_stamper.set_offsetX(0.6)
lp_stamper.set_offsetY(0.4)
lp_stamper.set_page(1)
# 设置签署位置 - 时间戳签署
time_stamper = Stamper()
time_stamper.set_actionId(company_actionId)
time_stamper.set_documentId(file_documentId)
time_stamper.set_type('TIMESTAMP')
time_stamper.set_offsetX(0.9)
time_stamper.set_offsetY(0.5)
time_stamper.set_page(1)
# 设置签署位置 - 个人接收方 - 个人签名
personal_stamper = Stamper()
personal_stamper.set_signatoryId(personal_signatoryId)
personal_stamper.set_documentId(file_documentId)
personal_stamper.set_type('PERSONAL')
personal_stamper.set_offsetX(0.4)
personal_stamper.set_offsetY(0.7)
personal_stamper.set_page(1)
# 请求服务器
send_response = sdkClient.request(
    ContractSendRequest(draft_contractid, [seal_stamper, lp_stamper, time_stamper, personal_stamper]))
# 解析返回数据
send_mapper = json.loads(send_response)
if send_mapper['code'] != 0:
    raise Exception('发起合同失败,失败原因:', send_mapper['message'])
print('合同发起成功')

4 抄送合同

描述:调用此接口来将合同抄送给未参与合同签署的人,仅合同完成后,抄送人才可以在页面上查看相关合同内容。

请求地址:/v2/contract/copysend

请求方法:POST

请求格式:application/json;charset=UTF-8

请求参数:

参数 类型 必须 描述
contractId String 合同ID,合同ID与业务ID二选一,不能同时为空
bizId String 业务ID,合同ID与业务ID二选一,不能同时为空
tenantName String 子公司名称,若使用业务ID发起合同,且合同是以子公司身份创建的,则需要传递该值,用于确定合同主体
receivers List<CopySendReceiver> 抄送人列表信息

CopySendReceiver(抄送人):

参数 类型 必须 描述
name String 抄送人姓名
receivers User 抄送人联系方式,联系方式类型只允许使用Mobile、Email

User(个人用户):

参数 类型 必须 描述
contact String 联系方式
contactType String 联系类型:MOBILE(手机号),EMAIL(邮箱)

返回参数:

参数 类型 描述
code Integer 响应码
message String 响应消息

响应码(全局响应码请查看文档末“全局响应码”):

响应码 描述
1117 DUPLICATE RECEIVER,抄送人已存在

请求示例:

Http示例

POST /v2/contract/copysend HTTP/1.1
Host: [host]
x-qys-open-timestamp: [替换为请求头生成的Timestamp]
x-qys-open-signature: [替换为请求头生成的Signature]
x-qys-open-accesstoken: [替换为请求头生成的Token]
Content-Type: application/json
{
    "contractId":"2631761055187775972",
    "receivers":[{
        "name":"张三",
        "receiver":{
            "contact":"1234567890",
            "contactType":"MOBILE"    
        }
    },{
        "name":"李四",
        "receiver":{
            "contact":"1234567890",
            "contactType":"MOBILE"    
        }
    }]
}
Java示例

// 初始化sdkClient
String serverUrl = "https://openapi.qiyuesuo.cn";
String accessKey = "替换为您申请的开放平台App Token";
String accessSecret = "替换为您申请的开放平台App Secret";
SdkClient sdkClient = new SdkClient(serverUrl, accessKey, accessSecret);
ContractCopySendRequest request = new ContractCopySendRequest(2652006623940010955L);
request.addReceiver(new CopySendReceiver("张三", new User("1234567890", "MOBILE")));
request.addReceiver(new CopySendReceiver("李四", new User("1234567890", "MOBILE")));
String response = sdkClient.service(request);
SdkResponse responseObj = JSONUtils.toQysResponse(response);
if(responseObj.getCode() == 0) {
    logger.info("合同抄送成功");
} else {
    logger.info("请求失败,错误码:{},错误信息:{}", responseObj.getCode(), responseObj.getMessage());
}
C#示例

string serverUrl = "https://openapi.qiyuesuo.cn";
string accessKey = "替换为您申请的开放平台App Token";
string accessSecret = "替换为您申请的开放平台App Secret";
SDKClient client = new SDKClient(accessKey, accessSecret, serverUrl);
ContractCopySendRequest request = new ContractCopySendRequest();
request.ContractId = "2619512417901977684";
request.AddReceiver(new CopySendReceiver("张忱昊", new User("17621699044", "MOBILE")));
request.AddReceiver(new CopySendReceiver("伍伶俐", new User("15802839734", "MOBILE")));
string response = null;
try
{
    response = client.Service(request);
}
catch (Exception e)
{
    throw new Exception(e.Message);
}
SdkResponse <Object> responseObject = HttpJsonConvert.DeserializeResponse <Object>(response);
PHP示例

// 初始化$sdkClient
class Util {
    const     url = "https://openapi.qiyuesuo.cn";
    const     accessKey = "替换为您申请的开放平台App Token";
    const     accessSecret = "替换为您申请的开放平台App Secret";
}
$sdkClient = Util::getSDk();
Python示例

#初始化SdkClient
url = "https://openapi.qiyuesuo.cn"
accessToken = '替换为您申请的开放平台App Token'
accessSecret = '替换为您申请的开放平台App Secret'
sdkClient = SdkClient(url, accessToken, accessSecret)