坚强的大象 · 将pandas ...· 2 月前 · |
英姿勃勃的黄豆 · 科兴股权大战迎尾声,创始人获刑 | 南方周末· 6 月前 · |
气宇轩昂的香菇 · kafka使用 SASL/PLAIN ...· 7 月前 · |
犯傻的黄豆 · CocoaPods Fails On ...· 11 月前 · |
文质彬彬的豆芽 · 欢迎使用 SOLIDWORKS ...· 1 年前 · |
接口支持https传输协议,URL接口遵循RESTful相关设计规范。如果使用HTTP协议调用,接口会尝试将请求重定向。
牛客网api验证与授权基于标准OAuth2.0。使用牛客网开放平台API接口之前,请先获取与账号相关联的
apiKey
与
token
。
具体获取方式为登录
牛客网企业版
后,点击
设置->账户设置->查看API KEY
来查看
apiKey
与
token
,
若未显示出
token
可以刷新页面重试。
api_key
为接口调用时必须要带上的参数,其值为
apiKey
需登录
牛客网企业版
获取。在使用
Postman
执行HTTP请求时,
GET请求的这个参数需要放在
Query Params
中,其他类型请求的这个参数需要放在
Body
中的
x-www-form-unlencoded
中,
值得注意的是,除了
api_key
之外,接口的特异化参数也需要按照这个规则传参。
某些接口需要传递多个参数,比如在批量创建考生时,就需要传多个考生的信息。对于这种情况,我们需要知道HTTP请求是可以传递键值重复的参数的,
在调用接口时,需要要顺序一次将多个参数填入,比如
a=1&a=3&a=3
。在需要传递多个对象形式的参数时,调用接口时可以这样处理:
v1=1&v2=1&v1=2&v2=2
,在牛客服务中,我们使用数组来处理重复参数,参数的在数组中的顺序与HTTP请求时传入的顺序相同。在批量创建考生的场景下,
对于多个考生的不同信息,比如:姓名和考号,我们会同时循环两个数组。分别从每个数组的固定位置取出姓名和考号,组成一个考生信息。最后如果信息无误,才会执行后面的操作。
而调用方在传递参数时,只需按考生顺序,传递所有考生的信息即可,比如:
name=user1&key=key1&name=user2&key=key2
,
具体示例可参考
添加考生
接口。
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import java.util.regex.Matcher;
public class IsPhone {
* 是不是手机号
public static boolean isPhone(String s) {
if (StringUtils.isBlank(s)) {
return false;
boolean containLeft = s.contains("(");
boolean containRight = s.contains(")");
if (!(containLeft == containRight)) {
return false;
String phone = s.trim().replace("+", "").replace("(", "").replace(")", "");
if (phone.startsWith("86")) {
phone = phone.substring(2);
if (phone.length() < 3) {
return false;
if (!NumberUtils.isDigits(phone)) {
return false;
if (isNativePhonePrefix(phone.substring(0, 3)) && !isOverSeaPhonePreFix(s)) {
// +153076137580 这个是海外手机,但是去掉+,会被判断是国内手机开头,所以加上isOverSeaPhonePreFix判断
return phone.length() == 11;
} else {
//如果是数字而又不是国内手机号,返回true
return true;
public static boolean isNativePhonePrefix(String prefix) {
java.lang.String regexMobile = "^1([3-9][0-9])$";
java.util.regex.Pattern p = java.util.regex.Pattern.compile(regexMobile);
Matcher m = p.matcher(prefix.trim());
return m.matches();
public static boolean isOverSeaPhonePreFix(String s) {
if (!s.startsWith("+")) {
return false;
if (s.startsWith("+86")) {
return false;
return true;
牛客手机号的校验规则
如果是国内手机号在符合正则表达式:^1([3-9][0-9])\d{8}$
的基础上,手机号开头可以不带"+86"
,带上的话和后面手机号之间不能有空格如: +8615205201314
如果是国外手机号需包含+
和国际地区前缀号码,如:+93701234567
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class IsEmail {
public static Pattern emailPattern =
Pattern.compile("^([a-zA-Z0-9_\\+\\.-])+@(([a-zA-Z0-9-])+\\.)+([a-zA-Z0-9]{2,8})");
* 是不是邮箱
public static boolean isEmail(String email) {
if (StringUtils.length(email) <= 40 && StringUtils.length(email) > 0) {
Matcher matcher = emailPattern.matcher(email);
return matcher.matches();
} else {
return false;
牛客邮箱的校验规则
需要符合正则表达式:^([a-zA-Z0-9_+.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,8})
且字符长度不超过40个。校验逻辑见java
代码示例。
接口返回格式
如无特殊说明,接口采用json格式来描述返回信息且接口返回头中带有Content-Type: application/json
,
比如:{"code":0,"msg":"OK","data": 接口返回信息}
,code=0
在业务上表示成功;code!=0
在业务上表示失败,msg
中为具体错误信息。
data
字段可能为空,它的数据结构可能是字符串、数字、json
对象等。data
具体的内容见接口文档。
时间格式返回字段
如无特殊说明,接口中返回的时间均为unix时间戳(毫秒级)
接口是否正常工作
接口没有返回200
且code!=0
可以视为发生了异常。异常绝大部分是传参不合法,比如请求了不存在的资源、参数传递出现了问题。
接口有可能在传参异常时返回4xx
,4xx
错误通常可以在返回的json中msg
处获取出错原因。若出错原因无法直接解读,可以联系我们。
如果出现了5xx
错误,请联系我们。
建议非200
情况下打印出牛客网返回的完整response
,其中40x
错误建议将msg
中信息在界面中展示给用户,方便用户处理。
常见错误:{"code" : 999,"msg" : "缺少认证参数","details" : null}
这个报错信息代表接口授权失败,需要检查api_key
参数和Authorization
请求头是否传递正确。
如果认为接口出现了问题。在向牛客技术反馈问题需提供如下信息:账号id、接口地址、接口入参、调用时间、牛客返回的完整response
。
示例代码提供了HTTP接口的调用样例。目前提供了shell和Java语言示例代码。点击右侧的shell
标签或java
标签即可查看。
示例代码,用于帮助开发者快速理解牛客api调用规范。代码仅供测试用。
shell示例代码
shell
代码示例提供了接口的curl
调用示例。开发者替换脚本中的api_key
参数和Authorization
校验头即可进行接口调用。
除此之外,代码示例中还包含了以json
形式表示的接口的返回数据结构。
java示例代码
java
代码示例提供了在Java程序中调用的示例。
为了消除重复代码,简化代码示例代码逻辑,示例代码中使用了NowcoderApiRequestUtils
工具类对HTTP调用过程进行了封装。示例代码中仅保留了接口地址和请求参数信息。
NowcoderApiRequestUtils
工具类和文档中的代码示例均托管在gitee。
下载代码至本地即可调试。
示例代码下载地址:https://gitee.com/nowcoder-guokaijun/nowcoder-api-http-call-demo/tree/master
下面是代码主要结构介绍
ConfigUtils
类
该类为牛客网企业版账户配置类,需要该类中的将TODO
标注的配置改为开发者自己账户的配置。
全局配置类
public class ConfigUtils {
private static final boolean USE_NOWCODER_API_ONLINE =
false; // TODO 牛客接口环境,false的是线下测试环境、需要根据您的代码运行环境灵活配置
private static final long NOWCODER_HR_ID_DEV = 0; // TODO 需要替换为您牛客线下测试环境的HrID
private static final long NOWCODER_HR_ID_ONLINE = 0; // TODO 需要替换为您牛客线上正式环境的HrID
private static final String API_KEY = "[email protected]"; // TODO 需要替换为您的api_key
private static final String TOKEN =
"95da5da5da5da5da5da5da5da5da5ff81aa9c7a8512638f4c73a4e338f650a5c"; // TODO 需要替换为您的token
private ConfigUtils() throws IllegalAccessException {
throw new IllegalAccessException("Can not instantiate an util class.");
private static boolean useNowcoderAPIOnline() {
return USE_NOWCODER_API_ONLINE;
public static long getNowcoderHrId() {
if (useNowcoderAPIOnline()) {
return NOWCODER_HR_ID_ONLINE;
return NOWCODER_HR_ID_DEV;
public static String getApiBaseUrl() {
// 线上正式环境
if (useNowcoderAPIOnline()) {
return "https://api.nowcoder.com/v1";
// 线下测试环境
return "https://dapi.nowcoder.com/v1";
public static String getApiKey() {
return API_KEY;
public static String getAuthorization() {
return "Bearer " + TOKEN;
NowcoderApiRequestUtils
类
该类为封装了符合牛客API的传输协议的HTTP调用逻辑的静态工具类。在该类中,有两个出口方法request()
和getNowcoderHrId()
。
其中request()
方法的作用是将接口的特异化参数传入并执行HTTP调用,方法支持HTTP的GET、POST、PUT、DELETE方法的请求,
并根据不同的HTTP方法规范设置了api_key
参数、Authorization
校验头、Content-Type
请求参数内容类型。
getNowcoderHrId()
方法的作用是获取用户的HRId,以便在调用需要拼接接口url的方法时使用。
请求牛客API工具类
public class NowcoderApiRequestUtils {
* HTTP调用牛客API并返回字符串,在调用之前根据请求方法设置了通用的请求头和请求参数,并将方法传入的参数置入HTTP请求中。
* @param path 请求路径,形如"/users/self"的字符串
* @param params 请求参数,需传递除api_key参数之外的每个接口独有的参数。一个key能对应多个值,值不能为null。
* 如果接口不需要其他参数,需要传递空Map,不能传null。
* @param methodName http方法名称。取值范围为 GET、POST、PUT、DELETE 中的一个
* @return 牛客接口json返回的字符串表示
public static String request(
String path, MultiValuedMap<String, Object> params, String methodName) {
if (HttpGet.METHOD_NAME.equals(methodName)) {
return getRequest(path, params);
HttpEntityEnclosingRequestBase uriRequest;
if (HttpPost.METHOD_NAME.equals(methodName)) {
uriRequest = new HttpPost();
} else if (HttpPut.METHOD_NAME.equals(methodName)) {
uriRequest = new HttpPut();
} else if (HttpDelete.METHOD_NAME.equals(methodName)) {
uriRequest = new NowcoderHttpDelete();
} else {
throw new IllegalArgumentException("Bad methodName.");
uriRequest.setURI(URI.create(ConfigUtils.getApiBaseUrl() + path));
List<NameValuePair> pairList = new ArrayList<>();
pairList.add(new BasicNameValuePair("api_key", ConfigUtils.getApiKey()));
params
.entries()
.forEach(
(entry) -> {
String key = entry.getKey();
Object val = entry.getValue();
if (key == null || val == null) return;
pairList.add(new BasicNameValuePair(key, val.toString()));
uriRequest.setEntity(new UrlEncodedFormEntity(pairList, StandardCharsets.UTF_8));
uriRequest.addHeader("Authorization", ConfigUtils.getAuthorization());
return sendRequest(uriRequest);
// 执行GET请求
private static String getRequest(String path, MultiValuedMap<String, Object> params) {
List<String> pairs = new ArrayList<>();
pairs.add("api_key=" + ConfigUtils.getApiKey());
params
.entries()
.forEach(
(entry) -> {
String key = entry.getKey();
Object val = entry.getValue();
if (key == null || val == null) return;
pairs.add(key + "=" + val);
String queryParams = StringUtils.join(pairs, "&");
HttpGet get = new HttpGet(ConfigUtils.getApiBaseUrl() + path + "?" + queryParams);
get.addHeader("Authorization", ConfigUtils.getAuthorization());
return sendRequest(get);
// 发送请求并打印CURL
private static String sendRequest(HttpRequestBase requestBase) {
CloseableHttpClient httpClient = HttpClients.createDefault();
String responseString = null;
try {
CloseableHttpResponse response = httpClient.execute(requestBase);
HttpEntity entity = response.getEntity();
responseString = EntityUtils.toString(entity, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
String curlStr = toCurlStr(requestBase);
System.out.println(curlStr);
return responseString;
// 将一次HTTP请求转换成CURL
private static String toCurlStr(HttpRequestBase requestBase) {
String httpMethod = requestBase.getMethod();
String uri = requestBase.getURI().toString();
List<String> headers = new ArrayList<>();
for (Header header : requestBase.getAllHeaders()) {
headers.add(header.getName() + ": " + header.getValue());
String headersStr = "";
if (CollectionUtils.isNotEmpty(headers)) {
for (String header : headers) {
headersStr += "\\\n --header '" + header + "' ";
String dataRawStr = "";
if (requestBase instanceof HttpEntityEnclosingRequestBase) {
HttpEntity entity = ((HttpEntityEnclosingRequestBase) requestBase).getEntity();
try {
dataRawStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
if (StringUtils.isNotEmpty(dataRawStr)) {
dataRawStr = String.format("\\\n --data-raw '%s'", dataRawStr);
String template = "curl --location --request %s '%s' %s %s";
return String.format(template, httpMethod, uri, headersStr, dataRawStr);
NowcoderHTTPDelete
类
由于HTTPDelete
类不支持传递参数内容,故实现了NowcoderHttpDelete
类以便在使用DELETE请求时传递参数。该类仅在NowcoderApiRequestUtils
中使用。
DELETE请求类
public class NowcoderHttpDelete extends HttpEntityEnclosingRequestBase {
public static final String METHOD_NAME = HttpDelete.METHOD_NAME;
public NowcoderHttpDelete() {
super();
public NowcoderHttpDelete(final URI uri) {
super();
setURI(uri);
/** @throws IllegalArgumentException if the uri is invalid. */
public NowcoderHttpDelete(final String uri) {
super();
setURI(URI.create(uri));
@Override
public String getMethod() {
return METHOD_NAME;
src/test/java
包下的测试类
使用NowcoderApiRequestUtils
工具类对牛客API的接口进行了测试。
具体的测试代码
public class Test {
@Test
public void testGetUserTestInfo() {
String path = "/users/self";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
接口文档组织形式
## 一句话描述接口
> 右侧为 java语言 和 shell语言的代码示例
阐明接口的业务背景、作用以及对接中常见问题。
### 接口地址
以`$method $uri`的形式表示接口地址,实际请求时,需要拼接`https://api.nowcoder.com/v1`的前缀。
### 请求参数
以表格形式展现的接口全部或部分主要的请求参数。
### 返回数据
以表格形式展现的接口全部或部分主要的返回数据。
接口文档模版
每一个接口除了描述接口的调用协议,还讲述了业务背景和对接中的常见问题。具体的组织形式见右侧示例代码。
在请求参数和返回参数仅列出部分字段为的是降低开发人员理解成本和对接难度,如发现字段不全或者接口不能满足需求的情况,请联系我们。
接口目录简述
已“笔试-”开头的为笔试系统对接需要关注的接口。
已“面试-”开头的为面试系统对接需要关注的接口。
系统接口为获取用户信息所需接口。
牛客网回调服务介绍
牛客网回调服务提供了实现了一种事件发布订阅机制。开发者在订阅某些事件之后,牛客网回调服务将会在事件发生时,通过HTTP请求的形式通知开发者。
开发者系统:需要与牛客进行信息互通且支持HTTP调用的系统。
回调:指从牛客回调服务发送HTTP请求至开发者系统这一动作。一般来说,开发者系统通过HTTP请求的方式调用牛客API来获取牛客系统中的信息,
如果我们将这个过程逆向,由牛客中调用开发者系统,向开发者系统传递信息,就成了“回调”。
回调时机:回调发生的时间节点,一般是指牛客系统中发生了某一关键业务需要告知开发者系统。
回调参数:在回调时,需要告知开发者系统的信息。
回调类型:按照业务、回调参数等信息划分的回调抽象。不同的回调类型也对应着不同的回调时机、回调参数以及回调配置形式。
回调配置:如需触发回调,需要开发者通过某些方式进行配置。
目前来说回调支持两种配置方式:
在调用创建实体接口(比如:笔试考生、面试房间)时订阅一个实体的回调。
由牛客开发者来配置回调。
一种回调类型只支持其中的一种回调配置方式,一种配置可能同时对多种回调类型生效。
回调接口协议
回调协议包含一次HTTP调用时牛客的请求形式和期望开发者系统的返回形式。
回调请求格式
对于GET请求,所有参数都放在HTTP的Query params
中;对于POST请求,请求头为application/x-www-form-urlencoded
,参数放在了Body中。
如果开发者系统使用了Java中的SpringMVC框架,请求参数声明既不用声明@RequestBody
注解,也不用声明@RequestParam
注解,
详情见: https://stackoverflow.com/q/33796218/10532034
回调成功/失败判定
开发者系统的服务返回success
这6个字符,视为回调成功。如果没有返回这六个字符,则视为回调失败。回调失败将会触发重试机制。
回调成功示例:纯HTTP响应格式如下:
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 7
success
回调重试机制
对于一次回调,牛客回调服务可能会尝试进行两次HTTP调用。
牛客回调服务会先尝试发送GET请求、如果请求失败,然后尝试发送POST请求。如果两次请求都失败了,牛客回调服务会认为这次请求失败了,并触发重试机制。
因为回调机制会采取重试机制,所有要求开发者的HTTP接口都是幂等的。
如果期望只进行POST请求,可以联系牛客开发人员进行配置。
回调频率、次数
如果遇到回调失败,牛客回调服务会尝试重试4次,带上第一次失败的请求,总共尝试5次。
第几次调用
第一次调用
第二次调用
第一次失败10分钟后
第三次调用
第二次失败30分钟后
第四次调用
第三次失败60分钟后
第五次调用
第四次失败120分钟后
其他事项
回调类型
不同的回调类型
有不同的回调配置
方式,会携带不同的回调参数
并在不同的回调时机
回调开发者。
回调服务地址
线下测试服务ip为:47.114.96.253
,线上回调服务ip:47.99.92.255
如开发者有配置接口调用白名单的需求,可以将上面两个IP加入接口调用白名单。
牛客系统对接最佳实践
牛客网企业版作为成熟的技术人才招聘解决方案提供商,根据多年系统对接经验,总结了下面几种系统对接最佳实践。
ATS:applicant tracking system,求职跟踪系统。在这里也可以指开发者需要与牛客对接的系统。
牛客/牛客网企业版:指牛客提供的接口服务以及回调服务
笔试系统对接最佳实践
对接模式一(推荐)
系统交互流程
企业的HR或者牛客项目同学,使用牛客网企业版管理后台在牛客系统创建试卷。
ATS通过调用牛客API接口,可以查询在牛客中已经创建好的试卷。
ATS中通过调用牛客API接口的方式,安排考生到牛客的试卷中。安排成功后,可以获取到考生的考试链接。在调用接口创建考生的同时,传递需要回调的地址。
在考生完成考试、作弊检测完成、人工判题完成等动作触发之后,牛客将考试成绩、成绩报告通过回调地址回传给ATS。
同时,ATS也可以选择在某一个时间点调用牛客API接口获取考生成绩。
代表企业:字节跳动、网易、moka、大易等绝大部分企业
对接模式二
系统交互流程
企业的HR或者牛客项目同学,使用牛客网企业版管理后台在牛客系统创建好试卷,并填好职位id(这个职位id用于关联企业ATS中的职位)。
试卷创建完成之后,可通过职位id定位一张试卷来创建考生。在调用接口创建考生的同时,传递需要回调的地址。
在考生完成考试、作弊检测完成、人工判题完成等动作触发之后,牛客将考试成绩、成绩报告通过回调地址回传给ATS。
同时,ATS也可以选择在某一个时间点调用牛客API接口获取考生成绩。
如需开启“配置职位id”功能,需要联系牛客开发人员进行配置。
代表企业:阿里巴巴、中兴、OPPO等部分企业
对接模式三
系统交互流程:
企业的HR或者牛客项目同学,使用牛客网企业版管理后台在牛客系统创建试卷。
试卷创建完成之后,在ATS系统中关联岗位、试卷。在ATS中将候选人转移状态即可安排笔试、拿到考生考试链接。
在考生完成考试、作弊检测完成、人工判题完成等动作触发之后,牛客将考试成绩、成绩报告回传给ATS。
同时,ATS也可以选择在某一个时间点调用牛客API接口获取考生成绩。
与对接模式二相比,该对接模式中岗位与试卷的关系在ATS中进行维护。ATS与牛客信息交互使用牛客试卷id。
代表企业:北森
面试系统对接最佳实践
对接模式一
系统交互流程
客户在牛客端创建账号,到对接方配置认证使用的api_key
在对接方推进面试流程,在牛客端进行面试
对接方、牛客端之间进行面试结果同步
面试结果同步可以分为对接方同步到牛客,对接方式一般为面试结束跳转对接方评价链接、牛客内嵌对接方面评表,然后通过评分接口同步到牛客。
牛客同步到对接方一般为面试轮次评价回调功能
笔试-试卷管理
一张试卷包含考试时长、考试起止时间、防作弊机制配置以及添加考生时需要录入信息等配置元信息。
在牛客系统中试卷可以认为是一场考试的抽象,在校园招聘业务场景下,一场考试应与一张试卷一一对应;
在社会招聘业务场景下,一张试卷可以认为是相似职位的通用考题。
一张试卷可以对应多个考生,所有的考生都属于一张试卷。考生在试卷之间没有关联关系,不同的试卷中可以创建唯一编号(添加考生接口的key字段)相同的考生。
试卷实体的关键字段
试卷实体的创建、删除和查询可调用试卷管理接口获取,下面是试卷实体的一些关键字段。
试卷id,唯一标识一张试卷。
paperName
String
试卷名字。
duration
试卷考试时长。
beginTime
试卷的开始时间。
endTime
试卷结束时间(对长期有效试卷,默认取值'2114-10-10T00:00')。
forever
boolean
试卷是否长期有效,true是,false否。
createTime
试卷的创建时间。
beenTested
boolean
试卷是否已经被使用。
started
boolean
试卷是否已经开始。
finished
boolean
试卷是否已结束。
summary
String
试卷简介,考生在考试开始前会看到这些信息。
questionCount
试卷试题的数量。
testCount
试卷测评的数量。
needJudge
试卷是否需要人工判题, 0表示需要,1表示不需要。
assignedCount
已经分配的判卷数量。
setting
Object
试卷相关配置信息, json格式。其中,试卷适用的职位id列表为该json下的"otherJobIds"字段,取值为int类型的职位id列表,职位id之间用","分隔,取值示例:""10000001,10000002"
score
Float
试卷总分。
passScoreLine
Float
antiCheatStr
String
防作弊机制。
signUpFieldTitles
String
考生需要录入信息的所有字段,逗号拼接。
paperCodeLangInfo
Object
试卷中编程题语言信息,对象结构见右侧说明
paperCodeLangInfo结构:
"codeQuestionCount": 2, // 编程题的数量,为0表示没有编程题
"ojExerciseUrl": "https://xxx", // codeQuestionCount大于0时有值,表示:OJ在线编程常见输入输出练习地址
"codeLangList": [ //codeQuestionCount大于0时有值,表示:对应题目数量和其支持的编程语言
"count": 2, // 题目数量
"langList": ["C","C#","C++","Go","Groovy","Java","Javascript"] // 编程语言列表,为null表示不限语言
获取试卷列表
public class Main {
@Test
public void testGetPaperList() {
String path = String.format("/papers/oid-%d", ConfigUtils.getNowcoderHrId());
long projectId = 1643;
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("page", 1);
mvMap.put("pageCount", 20);
mvMap.put("orderBy", 0);
mvMap.put("order", 2);
mvMap.put("filter", 0);
mvMap.put("query", "");
mvMap.put("progressType", 0);
mvMap.put("projectIdList", projectId);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/papers/[email protected]&filter=0&pageCount=20&progressType=0&query=&orderBy=0&page=1&projectIdList=1643&order=2' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : {
"totalCount" : 1,
"totalPage" : 1,
"currentPage" : 1,
"datas" : [ {
"id" : 17131890,
"paperName" : "一张很久才开始的试卷",
"createTime" : 1628137829000,
"duration" : 120,
"score" : 20,
"personTotal" : 0,
"avgTotal" : 0.0,
"summary" : "1、考前请关闭其他浏览器窗口,关闭QQ、微信等即时通信软件,关闭屏保、Outlook等弹窗提示软件,考试中不要切换到考试窗口之外的区域。<br/>\n2、请在规定时间内完成题目,答题过程中系统自动即时,到时自动交卷,请掌握好答题进度;<br/>\n3、请诚信答题,考试全程不要跳出考试页面(在线编程题除外),后台将记录你的跳出次数。编程题交卷后,我们将进行代码相似度判断,标示作弊嫌疑代码。<br/>\n4、笔试过程中遇到任务问题,请通过在线咨询小窗发消息给我们,我们会有相应人员解答。<br/>",
"logo" : null,
"questionCount" : 1,
"diffcult" : 0,
"beginTime" : 1735660800000,
"endTime" : 1738339200000,
"previewUrl" : "https://examd.nowcoder.com/cts/preview/papers/17131890?p_token=L9mTCQXQaLsBUEfFzKlJMrKLgROj5Xk4",
"testUrl" : "https://examd.nowcoder.com/cts/17131890/summary",
"mobileTestUrl" : null,
"assigned" : true,
"testCount" : 0,
"assignedCount" : 0,
"paperSetting" : null,
"presetUserCount" : 3,
"paperExcelDownloadUrl" : null,
"excelTaskStatus" : 0,
"finished" : false,
"started" : false,
"setting" : {
"logo" : "https://dev-private-public.oss-cn-hangzhou.aliyuncs.com/images/20201130/30_1606732062638/3669B06677BFB1053B71DAA1400C3083",
"paperSummary" : "1. 请使用最新版Chrome浏览器作答(不低于82版),如考试需开启摄像头,请确保电脑带有摄像头。\n2. 一旦开始考试,请勿离开答题页面,除非当前目录明确提醒可以离开,前三次离开会有提醒,之后将不再提醒。各目录是否支持离开答题页面则取决于试卷具体设置,进入每个目录会有提示。\n3. 考试过程中允许使用草稿纸,请提前准备纸笔。允许上厕所等短暂离开,请控制离开时间。\n4. 考试期间如遇到断电、断网、死机等问题,关闭浏览器重新打开试卷链接即可继续做题。\n5. 遇到问题请即时反馈给考试主办方。",
"examDisclaimer" : null,
"antiJumpOut" : false,
"antiDesignJumpOut" : true,
"antiCodingJumpOut" : false,
"codeSimilarRate" : 80,
"setSourceCoderCheat" : false,
"monitorPhone" : false,
"allowMobileTest" : false,
"noQueueUp" : true,
"signUpFields" : [ {
"title" : "姓名",
"name" : "name",
"format" : "",
"need" : true,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "投递编号",
"name" : "key",
"format" : "",
"need" : true,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "手机号码",
"name" : "phone",
"format" : "Phone",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "邮箱",
"name" : "email",
"format" : "Email",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "职位",
"name" : "zhi2_wei4",
"format" : "",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "学校",
"name" : "xue2_xiao4",
"format" : "",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "学历",
"name" : "xue2_li4",
"format" : "",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
} ],
"relationType" : 0,
"questionCategories" : {
"5" : "问答"
"questionIdsTypes" : { },
"questionScores" : null,
"questionNewCounts" : null,
"relationJsonString" : null,
"questionCategoryRule" : null,
"questionCategoryOrder" : "1,2,3,4,5",
"randomQuestion" : false,
"customCategory" : false,
"randomFrequentType" : 0,
"version" : "1.0",
"questionTagNames" : { },
"codingScoreRule" : 1,
"chooseScoreRule" : 3,
"checkCheat" : true,
"allowCopy" : false,
"allowCalculator" : false,
"contestDomain" : null,
"navLogoUrl" : null,
"hideNowcoder" : false,
"simulation" : false,
"languageLimit" : false,
"languageList" : [ ],
"reportPlatform" : true,
"forbidPreview" : true,
"needMobileCamera" : false,
"codePlayback" : false,
"timeLimitType" : 0,
"timeLimitDetail" : null,
"tiankongScores" : "{}",
"otherJobIds" : null,
"subPaperSetting" : null,
"uploadFileTimeRange" : 0,
"videoAnswerQuestionRule" : null,
"lateNoticeSetting" : null,
"paper_end_summary" : "本场考试已结束,请保持您的手机、邮箱畅通,方便接收后续通知。",
"allow_new" : false,
"allow_camera" : false,
"allow_screen_record" : false,
"allow_message" : false,
"question_disorder" : false,
"option_disorder" : false,
"not_need_judge_type" : "3_4",
"need_judge_type" : "5",
"faq" : [ ],
"hide_return_button" : true
"beenTested" : false,
"passScoreLine" : null,
"projectId" : 1643,
"projectName" : "liumeng测试",
"departmentList" : null,
"previewOverdueTime" : null,
"paperType" : null,
"hasNotAttendTestUser" : false,
"antiCheatStr" : "开启举报平台",
"signUpFieldTitles" : "投递编号,姓名,手机号码,邮箱,职位,学校,学历",
"creatorHrId" : 30,
"creatorHrName" : null,
"needJudge" : 0,
"notStartedCount" : 0,
"inProgressCount" : 0,
"expiredCount" : 0,
"cheatTaskStatus" : 0,
"faceDetectedRation" : 0.0,
"codeDetectedRation" : 0.0,
"screenDetectedRation" : 0.0,
"hasCodeQuestion" : false,
"hasCtsPic" : false,
"hasScreen" : false,
"questionDesc" : "问答 1 道",
"interviewPaper" : null,
"forever" : false
} ],
"ext" : null,
"allTotalCount" : 1,
"notStartedPaperCount" : 1,
"testingPaperCount" : 0,
"finishedPaperCount" : 0,
"archivePaperCount" : 0
获取一个账户下的试卷列表。支持分页。这个接口可以用于遍历牛客系统中已经创建好的试卷。
GET /papers/oid-{ownerId}
ownerId
HR系统的用户ID,需填充在url中
第几页,从1开始。
pageCount
每页20多少数据。无数量限制,可以传较大的值,但试卷数量多之后响应时长可能很长,不推荐这么做
orderBy
试卷排序的依据项。0根据create_time排序,1根据做题人数排序,2根据平均分排序,3开考时间
order
试卷的排列顺序。1代表升序,2代表降序
filter
是否过滤。可不传,默认0。0不过滤, 1过滤掉不需要人工判卷的试卷
query
String
试卷名称搜索,实现方式为SQLLIKE
关键字的模糊搜索
paperType
试卷类型:0.全部,1.普通笔试,2.ai面试。当paperType未传值或该参数不存在时,默认值为0,会返回笔试试卷+AI面试试卷(AI试卷名称自动添加#AI面试#前缀,以便于与笔试试卷区分);如果需要只返回笔试试卷,可以找客户经理进行配置
progressType
试卷的状态:0.代表不限,1.表示未开始,2.表示进行中,3.表示结束
progressTypeList
List<Integer>
progressType的多值查询参数,多个参数之间用OR关系取并集;当启用该参数时,建议progressType参数默认取值0(progressType和progressTypeList两参数间,是And关系取交集的逻辑)
projectIdList
List<Long>
限定试卷所属项目id,可传多个
otherJobIdList
List<Long>
限定职位id,一般情况下不用传,可传多个,用于筛选出“试卷配置中指定了职位id“的试卷列表。关于职位id更多信息见系统对接模式2
totalCount
数据(试卷)总数
totalPage
总共多少页
currentPage
当前是第几页,从第一页开始
datas
试卷信息数组,试卷关键信息见试卷关键返回字段
批量获取试卷
public class Main {
@Test
public void testGetPaperListByMultiPaperIds() {
String path = "/papers/multi";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("paperIds", 17071483);
mvMap.put("paperIds", 17071578);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/papers/[email protected]&paperIds=17071483&paperIds=17071578' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : [ {
"id" : 17071483,
"paperName" : "121",
"createTime" : 1611214578000,
"duration" : 120,
"score" : 112,
"personTotal" : 0,
"avgTotal" : 0.0,
"summary" : "1、考前请关闭其他浏览器窗口,关闭QQ、微信等即时通信软件,关闭屏保、Outlook等弹窗提示软件,考试中不要切换到考试窗口之外的区域。<br/>\n2、请在规定时间内完成题目,答题过程中系统自动即时,到时自动交卷,请掌握好答题进度;<br/>\n3、请诚信答题,考试全程不要跳出考试页面(在线编程题除外),后台将记录你的跳出次数。编程题交卷后,我们将进行代码相似度判断,标示作弊嫌疑代码。<br/>\n4、笔试过程中遇到任务问题,请通过在线咨询小窗发消息给我们,我们会有相应人员解答。<br/>",
"logo" : null,
"questionCount" : 4,
"diffcult" : 0,
"beginTime" : 1611214578000,
"endTime" : 4568544000000,
"previewUrl" : "https://examd.nowcoder.com/cts/preview/papers/17071483?p_token=L9mTCQXQaLsBUEfFzKlJMrKLgROj5Xk4",
"testUrl" : "https://examd.nowcoder.com/cts/17071483/summary",
"mobileTestUrl" : null,
"assigned" : true,
"testCount" : 0,
"assignedCount" : 0,
"paperSetting" : null,
"presetUserCount" : 0,
"paperExcelDownloadUrl" : null,
"excelTaskStatus" : 0,
"finished" : false,
"started" : true,
"setting" : {
"logo" : "https://dev-private-public.oss-cn-hangzhou.aliyuncs.com/images/20201130/30_1606732062638/3669B06677BFB1053B71DAA1400C3083",
"paperSummary" : "1. 请使用最新版Chrome浏览器作答(不低于82版),如考试需开启摄像头,请确保电脑带有摄像头。\n2. 一旦开始考试,请勿离开答题页面,除非当前目录明确提醒可以离开,前三次离开会有提醒,之后将不再提醒。各目录是否支持离开答题页面则取决于试卷具体设置,进入每个目录会有提示。\n3. 考试过程中允许使用草稿纸,请提前准备纸笔。允许上厕所等短暂离开,请控制离开时间。\n4. 考试期间如遇到断电、断网、死机等问题,关闭浏览器重新打开试卷链接即可继续做题。\n5. 遇到问题请即时反馈给考试主办方。",
"examDisclaimer" : null,
"antiJumpOut" : false,
"antiDesignJumpOut" : true,
"antiCodingJumpOut" : false,
"codeSimilarRate" : 80,
"setSourceCoderCheat" : false,
"monitorPhone" : false,
"allowMobileTest" : false,
"noQueueUp" : false,
"signUpFields" : [ {
"title" : "姓名",
"name" : "name",
"format" : "",
"need" : true,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "投递编号",
"name" : "key",
"format" : "",
"need" : true,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "手机号码",
"name" : "phone",
"format" : "Phone",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "邮箱",
"name" : "email",
"format" : "Email",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "职位",
"name" : "zhi2_wei4",
"format" : "",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "学校",
"name" : "xue2_xiao4",
"format" : "",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "学历",
"name" : "xue2_li4",
"format" : "",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
} ],
"relationType" : 0,
"questionCategories" : {
"100" : "1",
"101" : "2",
"102" : "3",
"103" : "4"
"questionIdsTypes" : { },
"questionScores" : null,
"questionNewCounts" : null,
"relationJsonString" : null,
"questionCategoryRule" : null,
"questionCategoryOrder" : null,
"randomQuestion" : false,
"customCategory" : true,
"randomFrequentType" : 0,
"version" : "1.0",
"questionTagNames" : { },
"codingScoreRule" : 1,
"chooseScoreRule" : 3,
"checkCheat" : true,
"allowCopy" : false,
"allowCalculator" : false,
"contestDomain" : null,
"navLogoUrl" : null,
"hideNowcoder" : false,
"simulation" : false,
"languageLimit" : false,
"languageList" : [ ],
"reportPlatform" : true,
"forbidPreview" : true,
"needMobileCamera" : false,
"codePlayback" : false,
"timeLimitType" : 0,
"timeLimitDetail" : null,
"tiankongScores" : "{\"803922\":[20,21,22,23]}",
"otherJobIds" : null,
"subPaperSetting" : [ {
"id" : 1,
"name" : "子卷1",
"intro" : "子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明子卷1说明",
"categories" : "102,100,101"
}, {
"id" : 2,
"name" : "子卷2",
"intro" : "子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明子卷2说明",
"categories" : "101,102,103"
} ],
"uploadFileTimeRange" : 0,
"videoAnswerQuestionRule" : null,
"lateNoticeSetting" : null,
"paper_end_summary" : "本场考试已结束,请保持您的手机、邮箱畅通,方便接收后续通知。",
"allow_new" : false,
"allow_camera" : true,
"allow_screen_record" : false,
"allow_message" : false,
"question_disorder" : true,
"option_disorder" : true,
"not_need_judge_type" : "3_4",
"need_judge_type" : "5",
"faq" : [ ],
"hide_return_button" : true
"beenTested" : false,
"passScoreLine" : null,
"projectId" : 1643,
"projectName" : "liumeng测试",
"departmentList" : null,
"previewOverdueTime" : null,
"paperType" : null,
"hasNotAttendTestUser" : false,
"antiCheatStr" : "开启摄像头,题目乱序,选择题选项乱序,开启举报平台",
"signUpFieldTitles" : "投递编号,姓名,手机号码,邮箱,职位,学校,学历",
"creatorHrId" : 30,
"creatorHrName" : null,
"needJudge" : 0,
"notStartedCount" : 0,
"inProgressCount" : 0,
"expiredCount" : 0,
"cheatTaskStatus" : 0,
"faceDetectedRation" : 0.0,
"codeDetectedRation" : 0.0,
"screenDetectedRation" : 0.0,
"hasCodeQuestion" : false,
"hasCtsPic" : true,
"hasScreen" : false,
"questionDesc" : "子卷1: 1 1 道,2 1 道,3 1 道<br>子卷2: 2 1 道,3 1 道,4 1 道<br>",
"interviewPaper" : null,
"forever" : true
}, {
"id" : 17071578,
"paperName" : "magictest",
"createTime" : 1615197295000,
"duration" : 60,
"score" : 36,
"personTotal" : 3,
"avgTotal" : 0.0,
"summary" : "1、考前请关闭其他浏览器窗口,关闭QQ、微信等即时通信软件,关闭屏保、Outlook等弹窗提示软件,考试中不要切换到考试窗口之外的区域。<br/>\n2、请在规定时间内完成题目,答题过程中系统自动即时,到时自动交卷,请掌握好答题进度;<br/>\n3、请诚信答题,考试全程不要跳出考试页面(在线编程题除外),后台将记录你的跳出次数。编程题交卷后,我们将进行代码相似度判断,标示作弊嫌疑代码。<br/>\n4、笔试过程中遇到任务问题,请通过在线咨询小窗发消息给我们,我们会有相应人员解答。<br/>",
"logo" : null,
"questionCount" : 12,
"diffcult" : 0,
"beginTime" : 1615197295000,
"endTime" : 1616818200000,
"previewUrl" : "https://examd.nowcoder.com/cts/preview/papers/17071578?p_token=L9mTCQXQaLsBUEfFzKlJMrKLgROj5Xk4",
"testUrl" : "https://examd.nowcoder.com/cts/17071578/summary",
"mobileTestUrl" : null,
"assigned" : false,
"testCount" : 4,
"assignedCount" : 0,
"paperSetting" : null,
"presetUserCount" : 7,
"paperExcelDownloadUrl" : null,
"excelTaskStatus" : 0,
"finished" : true,
"started" : true,
"setting" : {
"logo" : "https://dev-private-public.oss-cn-hangzhou.aliyuncs.com/images/20201130/30_1606732062638/3669B06677BFB1053B71DAA1400C3083",
"paperSummary" : "1. 请使用最新版Chrome浏览器作答(不低于82版),如考试需开启摄像头,请确保电脑带有摄像头。\n2. 一旦开始考试,请勿离开答题页面,除非当前目录明确提醒可以离开,前三次离开会有提醒,之后将不再提醒。各目录是否支持离开答题页面则取决于试卷具体设置,进入每个目录会有提示。\n3. 考试过程中允许使用草稿纸,请提前准备纸笔。允许上厕所等短暂离开,请控制离开时间。\n4. 考试期间如遇到断电、断网、死机等问题,关闭浏览器重新打开试卷链接即可继续做题。\n5. 遇到问题请即时反馈给考试主办方。",
"examDisclaimer" : null,
"antiJumpOut" : false,
"antiDesignJumpOut" : false,
"antiCodingJumpOut" : false,
"codeSimilarRate" : 80,
"setSourceCoderCheat" : false,
"monitorPhone" : false,
"allowMobileTest" : false,
"noQueueUp" : false,
"signUpFields" : [ {
"title" : "姓名",
"name" : "name",
"format" : "",
"need" : true,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "投递编号",
"name" : "key",
"format" : "",
"need" : true,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "手机号码",
"name" : "phone",
"format" : "Phone",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "邮箱",
"name" : "email",
"format" : "Email",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "职位",
"name" : "zhi2_wei4",
"format" : "",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "学校",
"name" : "xue2_xiao4",
"format" : "",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
}, {
"title" : "学历",
"name" : "xue2_li4",
"format" : "",
"need" : false,
"edit" : 0,
"valueType" : 0,
"valueList" : null
} ],
"relationType" : 0,
"questionCategories" : {
"1" : "单选"
"questionIdsTypes" : { },
"questionScores" : null,
"questionNewCounts" : null,
"relationJsonString" : null,
"questionCategoryRule" : null,
"questionCategoryOrder" : "1,2,3,4,5",
"randomQuestion" : false,
"customCategory" : false,
"randomFrequentType" : 0,
"version" : "1.0",
"questionTagNames" : { },
"codingScoreRule" : 1,
"chooseScoreRule" : 3,
"checkCheat" : true,
"allowCopy" : false,
"allowCalculator" : false,
"contestDomain" : null,
"navLogoUrl" : null,
"hideNowcoder" : false,
"simulation" : false,
"languageLimit" : false,
"languageList" : [ ],
"reportPlatform" : true,
"forbidPreview" : true,
"needMobileCamera" : false,
"codePlayback" : false,
"timeLimitType" : 0,
"timeLimitDetail" : null,
"tiankongScores" : "{}",
"otherJobIds" : null,
"subPaperSetting" : null,
"uploadFileTimeRange" : 0,
"videoAnswerQuestionRule" : null,
"lateNoticeSetting" : null,
"paper_end_summary" : "本场考试已结束,请保持您的手机、邮箱畅通,方便接收后续通知。",
"allow_new" : false,
"allow_camera" : true,
"allow_screen_record" : false,
"allow_message" : false,
"question_disorder" : true,
"option_disorder" : true,
"not_need_judge_type" : "3_4",
"need_judge_type" : "5",
"faq" : [ ],
"hide_return_button" : true
"beenTested" : false,
"passScoreLine" : null,
"projectId" : 1643,
"projectName" : "liumeng测试",
"departmentList" : null,
"previewOverdueTime" : null,
"paperType" : null,
"hasNotAttendTestUser" : false,
"antiCheatStr" : "开启摄像头,题目乱序,选择题选项乱序,开启举报平台",
"signUpFieldTitles" : "投递编号,姓名,手机号码,邮箱,职位,学校,学历",
"creatorHrId" : 30,
"creatorHrName" : null,
"needJudge" : 0,
"notStartedCount" : 0,
"inProgressCount" : 0,
"expiredCount" : 0,
"cheatTaskStatus" : 3,
"faceDetectedRation" : 0.0,
"codeDetectedRation" : 0.0,
"screenDetectedRation" : 0.0,
"hasCodeQuestion" : false,
"hasCtsPic" : true,
"hasScreen" : false,
"questionDesc" : "单选 12 道",
"interviewPaper" : null,
"forever" : false
根据试卷id批量获取试卷。开发者可以通过考生所属的试卷id来获取试卷的详细信息。如果试卷id不存在,会返回code=1
的报错。
GET /papers/multi
paperIds
List<Long>
试卷信息数组,试卷关键信息见试卷关键返回字段
删除试卷
public class Main {
@Test
public void testDeletePaper() {
long paperId = 17131854;
String path = String.format("/papers/%d", paperId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "DELETE");
System.out.println(responseString);
curl --location --request DELETE 'https://dapi.nowcoder.com/v1/papers/17131854' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com'
"code" : 0,
"msg" : "OK",
"data" : "OK"
根据试卷id删除试卷,删除之后,试卷的做题记录将同时清除。这个接口是幂等的,可以删除已经删除的试卷(无事发生)。
DELETE /papers/{paperId}
paperId
需填充在url中
不需要关注返回数据。只需要检查接口请求是否成功(返回HTTP状态码为 200
且内容中的code=0
)
根据试卷ID获取试卷信息
public class Main {
@Test
public void testGetPaperPreview() {
long paperId = 17071578;
String path = String.format("/papers/%d", paperId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "POST");
System.out.println(responseString);
curl --location --request POST 'https://dapi.nowcoder.com/v1/papers/17071578/previews' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com&shortUrl=true'
"code" : 0,
"msg" : "OK",
"data" : "https://dwz.cn/HTQwVSEe"
GET /papers/{paperId}
paperId
不能小于1,需填充在url中
试卷信息数组,试卷关键信息见试卷关键返回字段
分享试卷预览
public class Main {
@Test
public void testGetPaperPreview() {
long paperId = 17071578;
String path = String.format("/papers/%d/previews", paperId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("shortUrl", true);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "POST");
System.out.println(responseString);
curl --location --request POST 'https://dapi.nowcoder.com/v1/papers/17071578/previews' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com&shortUrl=true'
"code" : 0,
"msg" : "OK",
"data" : "https://dwz.cn/U4QdDWK8"
接口可以用于在开发者自己的系统中预览牛客的试卷。
POST /papers/{paperId}/previews
paperId
不能小于1,需填充在url中
shortUrl
boolean
默认true,可以为false
是否需要转换成短链接
字符串类型的链接地址。
笔试-考生管理
(考生实体)关键字段
考生包含了考生的个人信息,每一位考生归属一张试卷,每一位考生有自己的专属笔试链接。
考生实体的创建、删除和查询可调用考生管理接口获取,下面是考生实体的一些关键字段。
testId
String
考生id加密版,32位字符 (该字段建议入库保存,成绩报告回调时会回传testId字段,可用于进行考生成绩关联)
userKey
String
业务侧唯一用户标识,同张试卷下userKey唯一(通过paperId+userKey,也可以用于成绩报告回调时关联)
String
email
String
phone
String
testUrl
String
考生的专属考试链接
shortTestUrl
String
考生的专属考试链接(短链形式,打开自动跳转testUrl,目前仅对AI面试场景开放)
testBeginTime
考试链接最早可以开始作答时间,如果试卷当前正在使用,该时间默认为考试链接生成时间;但如果试卷未开始,则该时间可能晚于当前时间
testExpireTime
考试链接过期时间(对长期有效链接,默认取值'9999-12-31';20240614之前创建的长期有效链接,该字段则为null)
started
boolean
考生的考试是否已开始,true已开始
testStatus
考生考试状态,1没有开始考试,2表示已经打开,3表示已经提交
String
paperId
paperName
String
paperStarted
boolean
试卷是否已开始
signStatus
考生确认是否参加考试状态
noSignReason
String
拒绝参加考试的原因
emailNotification
邮件发起通知次数
smsNotification
短信发起通知次数
emailSentStatus
邮件发送状态, 0未发送,1发送中,2发送失败,3接收成功,4接收失败,5定时发送,6取消发送
smsSentStatus
短信发送状态, 0未发送,1发送中,2发送失败,3接收成功,4接收失败,5定时发送,6取消发送
createTime
(添加考生前)检测余额是否充足
public class Main {
@Test
public void testAddTestUsersCheckBalance() {
String path = "/papers/test_users/checkBalance";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
long paperId = 17071600;
int userCnt = 2;
mvMap.put("paperId_userCounts", paperId + "_" + userCnt);
long anotherPaperId = 17071600;
int anotherUserCnt = 2;
mvMap.put("paperId_userCounts", anotherPaperId + "_" + anotherUserCnt);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/papers/test_users/[email protected]&paperId_userCounts=17071600_2&paperId_userCounts=17071600_2' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : {
"hostId" : 30,
"adminHrId" : 30,
"moneyEnough" : true,
"subAccountLimitEnough" : true
在添加考生前,可以通过该接口预估添加考生时是否余额足够。
GET /papers/test_users/checkBalance
paperId_userCounts
List<String>
格式为:试卷id_考生数量。可传多个
按试卷id聚合考生数量,
hostId
当前账号id
adminHrId
当前账号的公司主账号id
moneyEnough
公司主账号的余额是否充足
subAccountLimitEnough
子账号分配的业务额度是否充足
public void testAddTestUsers() {
long paperId = 17131890;
String path = String.format("/papers/%d/test_users", paperId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("name", "郭凯俊1");
mvMap.put("key", "gkj1");
mvMap.put("phone", "18812341234");
mvMap.put("email", "[email protected]");
mvMap.put("shen1_fen4_zheng4", "431123199911116666");
mvMap.put("zhi2_wei4", "Java开发工程师");
mvMap.put("xue2_xiao4", "清北大学");
mvMap.put("xue2_li4", "本科");
mvMap.put("note", "这个考生是通过API添加的");
mvMap.put("name", "郭凯俊2");
mvMap.put("key", "gkj2");
mvMap.put("phone", "18812341234");
mvMap.put("email", "[email protected]");
mvMap.put("shen1_fen4_zheng4", "431123199911116666");
mvMap.put("zhi2_wei4", "Java开发工程师");
mvMap.put("xue2_xiao4", "清北大学");
mvMap.put("xue2_li4", "本科");
mvMap.put("note", "这个考生是通过API添加的");
mvMap.put("failOnExist", false);
mvMap.put("notice", false);
mvMap.put("version", 0);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "POST");
System.out.println(responseString);
curl --location --request POST 'https://dapi.nowcoder.com/v1/papers/17131890/test_users' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com¬e=%E8%BF%99%E4%B8%AA%E8%80%83%E7%94%9F%E6%98%AF%E9%80%9A%E8%BF%87API%E6%B7%BB%E5%8A%A0%E7%9A%84¬e=%E8%BF%99%E4%B8%AA%E8%80%83%E7%94%9F%E6%98%AF%E9%80%9A%E8%BF%87API%E6%B7%BB%E5%8A%A0%E7%9A%84&failOnExist=false&phone=18812341234&phone=18812341234&shen1_fen4_zheng4=431123199911116666&shen1_fen4_zheng4=431123199911116666&name=%E9%83%AD%E5%87%AF%E4%BF%8A1&name=%E9%83%AD%E5%87%AF%E4%BF%8A2&xue2_xiao4=%E6%B8%85%E5%8C%97%E5%A4%A7%E5%AD%A6&xue2_xiao4=%E6%B8%85%E5%8C%97%E5%A4%A7%E5%AD%A6&zhi2_wei4=Java%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88&zhi2_wei4=Java%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88&version=0&key=gkj1&key=gkj2&email=guokaijun%40nowcoder.com&email=guokaijun%40nowcoder.com&xue2_li4=%E6%9C%AC%E7%A7%91&xue2_li4=%E6%9C%AC%E7%A7%91¬ice=false'
"code" : 0,
"msg" : "OK",
"data" : [ {
"id" : 2115087,
"email" : null,
"phone" : null,
"testId" : "DCC8EDB8828E22D5",
"paperId" : 17131890,
"paperName" : null,
"userKey" : "gkj1",
"name" : null,
"ext" : null,
"testUrl" : "https://examd.nowcoder.com/cts/17131890/summary?id=DCC8EDB8828E22D5",
"started" : false,
"signStatus" : 0,
"noSignReason" : null,
"emailNotification" : 0,
"smsNotification" : 0,
"emailSentStatus" : 0,
"smsSentStatus" : 0,
"note" : null,
"createTime" : null,
"testStatus" : 0,
"realTestId" : 0,
"ctsDepartment" : null,
"creatorHrUid" : 0,
"creatorHrName" : null,
"apiRole" : 0,
"emailRecordCount" : 0,
"smsRecordCount" : 0,
"emailRecord" : null,
"smsRecord" : null,
"emailSuccessCount" : 0,
"smsSuccessCount" : 0,
"paperStarted" : false,
"arrangeFeedbackId" : 0,
"arrangeFeedbackTime" : null,
"arrangeFeedbackContent" : null,
"errMsg" : null,
"paperStartTime" : 1735660800000,
"paperEndTime" : 1738339200000
}, {
"id" : 2115088,
"email" : null,
"phone" : null,
"testId" : "C72B030BD2287647",
"paperId" : 17131890,
"paperName" : null,
"userKey" : "gkj2",
"name" : null,
"ext" : null,
"testUrl" : "https://examd.nowcoder.com/cts/17131890/summary?id=C72B030BD2287647",
"started" : false,
"signStatus" : 0,
"noSignReason" : null,
"emailNotification" : 0,
"smsNotification" : 0,
"emailSentStatus" : 0,
"smsSentStatus" : 0,
"note" : null,
"createTime" : null,
"testStatus" : 0,
"realTestId" : 0,
"ctsDepartment" : null,
"creatorHrUid" : 0,
"creatorHrName" : null,
"apiRole" : 0,
"emailRecordCount" : 0,
"smsRecordCount" : 0,
"emailRecord" : null,
"smsRecord" : null,
"emailSuccessCount" : 0,
"smsSuccessCount" : 0,
"paperStarted" : false,
"arrangeFeedbackId" : 0,
"arrangeFeedbackTime" : null,
"arrangeFeedbackContent" : null,
"errMsg" : null,
"paperStartTime" : 1735660800000,
"paperEndTime" : 1738339200000
接口用于向试卷中添加考生。如果试卷不允许用户自己报名参加,只有再这里添加的用户才能参加考试(直接打开接口返回的URL来考试)。
接口可以同时添加多个用户,即传多个keys和names参数,数量要保持一致。其他选填字段如手机、邮箱等,方式相同。
试卷配置中默认的手机字段为phone, 邮箱为email,其他为汉语拼音加声调加下划线。例如职位zhi2_wei4, 学历xue2_li4。
POST /papers/{paperId}/test_users
除列表中展示的字段外,还可以填入考生的其他选填字段。例如职位zhi2_wei4, 学历xue2_li4。详情见代码示例
paperId
需填充在url中
List<String>
考试编号,在同一个试卷内唯一确定一个用户的字符串,不能包含emoji字符
List<String>
和key对应的用户的姓名,姓名不能包含如下字符: `~!@#$%^&*()+=|{}':;[]<>/?!¥…()—【】‘;:”“’。、?
foreignKey
List<String>
同1位候选人(自然人)在其它场景(比如AI面试)使用的考试编号,与key字段相对应。比如笔试场景下,key代表的是该候选人在本场考试下的考试编号,而foreignKey可代表该候选人在后续AI面试中的编号,通过这2个Key可以跨场景关联到同1个人。
userData
List<String>
候选人信息,主要用于AI面试智能化出题、智能追问等场景,数据类型为json对象转string,json结构定义请参考文档候选人信息Json结构定义
callback
String
回调地址,填写后将配置:完成考试、作弊检测、人工判题、考生被删除 四种类型的回调。更多关于回调类型的信息见:链接
failOnExist
boolean
为true时,如果导入前这个考生的key已经存在,则直接返回失败
userType
考生类型: 0 普通考生 1 测试考生,可提前进入考试答题。每张试卷可免费添加10个测试考生,超过部分将扣费
confirm
boolean
当添加测试考生且即将扣费时,需要confirm=true时才能继续操作。
List<String>
和key对应的用户的备注,可以不传
version
0:当所有考生格式正确才会添加,1:格式正确考生会录入成功
notice
boolean
true:使用牛客默认模版发送手机短信和邮件通知,false:不发送
emailTemplateId
仅在notice=true时有效,用于指定本次通知的邮件版本
smsTemplateId
仅在notice=true时有效,用于指定本次通知的短信版本
emailTemplateId和smsTemplateId的取值,目前不支持产品化,但技术同学可以在HR后台,通过截图中的示例方案自助获取。点击查看emailTemplateId/smsTemplateId获取示例
已经添加过的考生信息数组。接口需要关心下面的字段
errMsg
添加考生失败的时候,返回的考生id=0,此时这个字段会返回错误原因
其他参数见考生关键信息见考生关键返回字段
删除考生
public class Main {
@Test
public void testDeleteTestUser() {
long paperId = 17131890;
long testUserId = 2115115;
String path = String.format("/papers/%d/test_users/%d", paperId, testUserId);
// 考试已经开始无法删除考生。
// 已经删除的考生无法删除。
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "DELETE");
System.out.println(responseString);
curl --location --request DELETE 'http://localhost:8888/v1/papers/17131890/test_users/2115115' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com'
# 删除成功
"code" : 0,
"msg" : "OK",
"data" : "该考生未参加考试,考试费用15.0元已退回您的账户。"
# 考生曾经删除成功 或者 考生没有被添加过
"code" : 1,
"msg" : "考生不存在",
"details" : null
通过考生id删除牛客系统中的一个考生。
DELETE /papers/{paperId}/test_users/{id}
paperId
需填充在url中
需填充在url中
无需关心返回数据,接口请求成功则视为删除成功
如果考生成功删除,示例信息如下:
"code" : 0,
"msg" : "OK",
"data" : "该考生未参加考试,考试费用15.0元已退回您的账户。"
如果考生曾经删除成功或者考生没有被添加过,会返回下面的错误信息。
"code" : 1,
"msg" : "考生不存在",
"details" : null
删除时机说明(包括批量删除接口):
1. 在笔试场景下,只允许删除尚未开始考试的考生。
2. 在AI面试场景下,对删除考生时机已放开限制;如果被删考生正在面试中,删除后会中断并结束面试;如果面试已结束,相关面试记录都也会被删除。请警慎操作!
批量删除考生
public class Main {
@Test
public void testDeleteMultiTestUsers() {
String delUsersPath = String.format("/papers/%d/test_users", 0);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("ids", 2115077);
mvMap.put("ids", 2115081);
mvMap.put("paperIds", 17131890);
mvMap.put("paperIds", 17131891);
mvMap.put("isAll", 2);
String responseString = NowcoderApiRequestUtils.request(delUsersPath, mvMap, "DELETE");
System.out.println(responseString);
curl --location --request DELETE 'https://dapi.nowcoder.com/v1/papers/0/test_users' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com&ids=2115077&ids=2115081&isAll=2&paperIds=17131890&paperIds=17131891'
"code" : 0,
"msg" : "OK",
"data" : "UBfCoqS08apsZ8QIEojbsmfpyxUCaYgh"
通过多个考生id批量删除牛客系统中的考生。该接口会异步进行处理。无需关心返回数据,接口请求成功则视为删除成功
如果确实需要获取异步任务信息,根据接口返回的异步任务id请求接口[获取异步任务进度](#system-async-job-process)
DELETE /papers/{paperId}/test_users
List<Long>
考生id。可以填多个
paperIds
List<Long>
试卷id,需要包含所有考生所属的试卷ids。可以填多个,但列表中id不能重复
isAll
用于指定接口取paperIds
paperId
用于填充参数中的url
牛客异步任务id。
查询单个考生信息
public class Main {
@Test
public void testGetTestUser() {
long paperId = 17131890;
long testUserId = 2115086;
String path = String.format("/papers/%d/test_users/%d", paperId, testUserId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/papers/17131890/test_users/[email protected]' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : {
"id" : 2115086,
"email" : "[email protected]",
"phone" : "18812341234",
"testId" : null,
"paperId" : 17131890,
"paperName" : null,
"userKey" : "gkj",
"name" : "郭凯俊",
"ext" : "{\"phone\":\"18812341234\",\"name\":\"郭凯俊\",\"xue2_xiao4\":\"清北大学\",\"zhi2_wei4\":\"Java开发工程师\",\"key\":\"gkj\",\"email\":\"[email protected]\",\"xue2_li4\":\"本科\"}",
"testUrl" : null,
"started" : false,
"signStatus" : 0,
"noSignReason" : "",
"emailNotification" : 0,
"smsNotification" : 0,
"emailSentStatus" : 0,
"smsSentStatus" : 0,
"note" : "这个考生是通过API添加的",
"createTime" : 1628147456000,
"testStatus" : 1,
"realTestId" : 0,
"ctsDepartment" : null,
"creatorHrUid" : 30,
"creatorHrName" : null,
"apiRole" : 2,
"emailRecordCount" : 0,
"smsRecordCount" : 0,
"emailRecord" : null,
"smsRecord" : null,
"emailSuccessCount" : 0,
"smsSuccessCount" : 0,
"paperStarted" : false,
"arrangeFeedbackId" : 0,
"arrangeFeedbackTime" : 1628147456000,
"arrangeFeedbackContent" : null,
"errMsg" : null,
"paperStartTime" : null,
"paperEndTime" : null
接口用于查询单个考生的信息
GET /papers/{paperId}/test_users/{id}
paperId
需填充在url中
需填充在url中
考生关键信息见考生关键返回字段。
更新单个考生信息
public class Main {
@Test
public void testUpdateTestUser() {
long paperId = 17131890;
long testUserId = 2115086;
String path = String.format("/papers/%d/test_users/%d", paperId, testUserId);
// 考试已经开始无法删除考生。
// 已经删除的考生无法删除。
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("name", "郭凯俊");
mvMap.put("key", "gkj");
mvMap.put("phone", "18812341234");
mvMap.put("email", "[email protected]");
mvMap.put("shen1_fen4_zheng4", "431123199911116666");
mvMap.put("zhi2_wei4", "Java开发工程师");
mvMap.put("xue2_xiao4", "清北大学");
mvMap.put("xue2_li4", "本科");
mvMap.put("note", "这个考生是通过API添加的");
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "PUT");
System.out.println(responseString);
curl --location --request PUT 'https://dapi.nowcoder.com/v1/papers/17131890/test_users/2115086' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com¬e=%E8%BF%99%E4%B8%AA%E8%80%83%E7%94%9F%E6%98%AF%E9%80%9A%E8%BF%87API%E6%B7%BB%E5%8A%A0%E7%9A%84&phone=18812341234&shen1_fen4_zheng4=431123199911116666&name=%E9%83%AD%E5%87%AF%E4%BF%8A&xue2_xiao4=%E6%B8%85%E5%8C%97%E5%A4%A7%E5%AD%A6&zhi2_wei4=Java%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88&key=gkj&email=guokaijun%40nowcoder.com&xue2_li4=%E6%9C%AC%E7%A7%91'
"code" : 0,
"msg" : "OK",
"data" : null
接口用于更新单个考生的信息
PUT /papers/{paperId}/test_users/{id}
paperId
需填充在url中
需填充在url中
String
String
考试编号,在同一个试卷内唯一确定一个用户的字符串,不能包含emoji字符
departmentId
所属部门,为0表示公开
userType
String
notice
boolean
是否发送通知,true发送、false不发送
emailTemplateId
仅在notice=true时有效,用于指定本次通知的邮件版本
smsTemplateId
仅在notice=true时有效,用于指定本次通知的短信版本
无需关心返回数据,接口请求成功则视为删除成功
批量查询当前考生状态
接口地址
/v1/partners/paper/batch_user_status
请求方法和类型
post, application/json
请求和回报参数见右边
请求参数:
"paperId": "必填,long,试卷id",
"userKeyList": "必填,string array,考试编号,单次最多查询50个考生"
回包参数:
"code": "int:0表示成功,非0表示失败",
"msg": "string:code非0时表示报错原因",
"data": {
"userList": [
"id": "long, 考生id",
"userKey": "string, 考试编号",
"status": "int, 考生状态,ai面试场景:1.面试未开始,2.待面试,3.已过期,4.面试中,5.已完成,6.判题完成;笔试场景:210.未进入考试,220.已开考,230.作答完成"
笔试-考生成绩管理
查询单个考生考试结果
public class Main {
@Test
public void testGetUserTestInfo() {
String path = "/papers/usertestinfo";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("paperId", 17131674);
mvMap.put("userkey", "qwe");
mvMap.put("needCategoryScore", true);
mvMap.put("needCheatInfo", true);
mvMap.put("needJudgeInfo", true);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/papers/[email protected]&needCategoryScore=true&needCheatInfo=true&needJudgeInfo=true&paperId=17131674&userkey=qwe' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : [ {
"paperName" : "编程题测试2",
"pdfUrl" : "https://dapi.nowcoder.com/v1/test-pdf/F23269B6DFB0F586?paperId=17131674&tokenValue=cbe1f318a47b50c7e7f096ff6cbf2ed8746df596943e48f971a2a191a36ab07d&download=false",
"userScore" : 0.0,
"paperScore" : 60,
"status" : 2,
"cheatStatus" : 3,
"beginTime" : 1626785242000,
"finishTime" : 1626797842000,
"createTime" : 1626785226000,
"apiCategoryScores" : [ {
"score" : 0.0,
"categoryType" : 5,
"questionType" : 5,
"categoryName" : "问答"
} ],
"rankPercent" : 0.25,
"cheatReasonList" : null,
"judgeAssignAccountAndJudgeStatuses" : null,
"judgeRemarkInfos" : null,
"cheatInfoDesc" : null,
"finalScore" : true
查询单个考生考试结果信息。如果考生没有参加考试无法查到信息。
GET /papers/usertestinfo
paperId
试卷id(不传的话会查询所有试卷中考试编号为userkey的考生,传了就查指定试卷中的)
userkey
String
考试编号,对应添加考生接口中key字段值
needCategoryScore
boolean
是否需要不同题型得分
needCheatInfo
boolean
是否需要作弊信息
needJudgeInfo
boolean
是否需要人工判题信息,仅在paperId>0时有效
pdfFileType
0表示返回在线预览的pdf地址,1表示返回可下载的pdf地址
接口的返回数据由考生信息与考生测评信息结合而成。
paperName
pdfUrl
报告pdf链接
webReportUrl
在线报告链接
userScore
paperScore
testResult
表示考试结果,取值passed表示“通过”,failed表示“不通过”
rejectionReasons
表示筛选不通过的原因(仅在testResult="failed"时有效);原因存在多项时,采用";"进行拼接;没值时用null表示
specialNotes
表示报告中需要特别关注的事情;存在多个关注事项时,采用";"进行拼接;没值时用null表示
moduleScores
表示考生按能力项维度聚合的得分情况。这个参数会有多个,每一个的参数格式是moduleScore|moduleName
如 "70.5|英语能力
",moduleScore为skillScore的上级维度
skillScores
表示考生按技能项维度聚合的得分情况。这个参数会有多个,每一个的参数格式是skillScore|skillName
如 "60.5|抗压能力
",skillScore为moduleScore的下级维度
status
考生未参加考试(-1),系统判题未完成(1), 考试进行中(0), 已交卷(2), 人工判题完成(4)
cheatStatus
作弊检测未完成(0), 作弊(1), 未作弊(2), 作弊疑似(3)
beginTime
开始答卷时间
finishTime
createTime
笔试的安排时间
elapseTime
测评消耗时间,单位是秒
rankPercent
浮点型排名百分比
rankScore
考生得分中位数
finalScore
是否是最终成绩:需要人工判题的,若人工判题完成则为最终成绩;无需人工判题的,只要交卷就是最终成绩
judgeRemarkInfos
判题备注,对象数组
cheatInfoDesc
作弊描述信息,单个字符串
apiCategoryScores
各个目录得分,对象数组
cheatReasonList
以文字表述的作弊原因字符串数组。具体信息见链接
judgeAssignAccountAndJudgeStatuses
判题备注 ,对象数组。分配的判题账户列表以及相应的完成状态
headUrl
考生自拍头像链接
目录得分数据结构
score
categoryType
questionType
题目类型:单选(1), 不定项选择(2), 填空(3), 编程(4), 问答(5) ,
categoryName
目录得分数据结构
userId
判题的账号id
userName
判题的账号名称
judgeStatus
判题完成的状态,值枚举:已判题/未判题
判题备注数据结构
userName
判题的账号名称
summaryRemark
questionRemarkInfos
各题目备注,对象数组
题目备注数据结构
questionName
例如:填空题第1题
remark
获取某个用户拥有卷子的测评信息
public class Main {
@Test
public void testGetPaperTestsInfo() {
String path = String.format("/tests/poid-%d", ConfigUtils.getNowcoderHrId());
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("projectIdList", 2227);
mvMap.put("paperIds", 17131674);
mvMap.put("page", 1);
mvMap.put("pageSize", 1);
mvMap.put("order", 2);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "POST");
System.out.println(responseString);
curl --location --request POST 'https://dapi.nowcoder.com/v1/tests/poid-30' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com&pageSize=1&page=1&projectIdList=2227&paperIds=17131674&order=2'
"code" : 0,
"msg" : "OK",
"data" : {
"totalCount" : 4,
"totalPage" : 4,
"currentPage" : 1,
"datas" : [ {
"id" : 1838108,
"encryptId" : null,
"actorId" : 2114808,
"paperId" : 17131674,
"paperName" : "编程题测试2",
"finishTime" : 1626797842000,
"status" : 2,
"score" : 0.0,
"paperScore" : 60.0,
"paperOpenCount" : 4,
"createTime" : 1626785242000,
"actorType" : 10,
"elapseTime" : 40,
"leaveCount" : 4,
"headUrl" : "",
"signatureUrl" : null,
"ipAddress" : "北京市",
"ip" : "123.118.109.227",
"cheated" : 3,
"ncUser" : {
"id" : 2114808,
"email" : null,
"nickname" : "aweqwe",
"phone" : null,
"displayName" : "aweqwe"
"user" : {
"id" : 2114808,
"email" : null,
"nickname" : "aweqwe",
"phone" : null,
"displayName" : "aweqwe"
"testUserKey" : "qwe",
"questionCount" : 0,
"rightCount" : 0,
"numberRank" : 1,
"percentRank" : 0,
"difficulty" : 0,
"key" : null,
"keyTitle" : null,
"name" : null,
"nameTitle" : null,
"creatorHrUid" : 0,
"creatorHrName" : "管理员",
"pdfUrl" : null,
"testResultUrl" : "https://dapi.nowcoder.com/v1/test-pdf/F23269B6DFB0F586?paperId=17131674&tokenValue=cbe1f318a47b50c7e7f096ff6cbf2ed8746df596943e48f971a2a191a36ab07d&download=false",
"notJudgedTypes" : [ 3 ],
"needJudge" : true,
"picCount" : 0,
"review" : null,
"questionTypeList" : null,
"categoryTypeList" : null,
"signUpFields" : null,
"userExt" : {
"phone" : "",
"name" : "aweqwe",
"xue2_xiao4" : "",
"zhi2_wei4" : "",
"email" : "",
"xue2_li4" : "",
"key" : "qwe"
"remarkList" : null,
"antiJumpOut" : false,
"allowCamera" : false,
"allowScreenRecord" : false,
"monitorPhone" : false,
"needMobileCamera" : false,
"hasCodeProblem" : false,
"hasHistoryData" : false,
"judgingPermission" : null,
"canSee" : true,
"price" : 30.0,
"cheatReasonList" : [ ],
"testUserNote" : null,
"paperSimulation" : false,
"categoryScores" : null,
"categoryTotalScores" : null,
"timeCount" : null,
"resumeId" : 0,
"resumePermit" : 0,
"recruitProjectId" : 0,
"judged" : true,
"notJudgedReason" : null,
"judgingTip" : "需要人工阅卷的题目答案为空,系统自动判题",
"resumeForJudge" : null,
"deliverId" : 0,
"testPeriod" : null,
"clientSystem" : 1,
"longValidTime" : true,
"previewOverdueTime" : null,
"tagNameList" : [ ],
"bought" : true,
"tagList" : null
} ],
"ext" : {
"lackCount" : "0"
根据查询条件,查询当前账户下的考生成绩。
POST /tests/poid-{paperOwnerId}
paperOwnerId
必传,需填充在url中
当前用户的HRId
paperIds
List<Long>
用于筛选试卷id,可不传
projectIdList
List<Long>
用于筛选项目id,可不传
非必传,从1开始,默认为1
pageSize
非必传,默认为20
orderBy
非必传,默认0
根据什么排序,默认为0;0根据考生开始测评的时间排序,1根据考生完成测评的时间排序,2根据考生测评的分数排序
order
非必传,默认1
升序还是降序,默认为1升序。1代表升序,2代表降序。
totalCount
列表数据总数
totalPage
列表总页数
currentPage
当前是第几页,从1开始
datas
考生成绩数据数组
考生成绩对象数据结构
encryptId
actorId
测评用户ID
paperId
测评点的试卷
paperName
finishTime
测评完成时间
status
score
测评的分数
paperScore
paperOpenCount
试卷到场人数
createTime
测评开始时间
actorType
测评用户的类型
elapseTime
测评消耗时间,单位是秒
leaveCount
headUrl
signatureUrl
签名url
ipAddress
考生考试ip地址
cheated
是否作弊:0-作弊检测任务未完成,1-作弊,2-未作弊,3-疑似作弊
testUserKey
考试测评用户的主key
questionCount
rightCount
试题正确的数量
numberRank
percentRank
百分比排名
唯一识别用户的Key
keyTitle
key的标题
测评用户名字
nameTitle
测评用户名字的标题
creatorHrUid
创建测评用户的hr的uid
creatorHrName
创建测评用户的hr名字
pdfUrl
测评结果的PDF地址
testResultUrl
笔试报告地址,三方系统请使用此链接查看笔试报告
notJudgedTypes
不判题的题目类型
needJudge
试卷是否需要人工判题
picCount
截图的数量
review
牛客系统评语
questionTypeList
signUpFields
需要录入的考生信息
judgingPermission
面试官查看权限
cheatReasonList
作弊原因,仅在cheated=1的时候有值,具体信息见链接
judged
是否已经判题
notJudgedReason
未判题的原因
clientSystem
答题设备1表示pc ,2表示ios 3表示android
tagNameList
判题所打的标签名字列表
笔试-回调服务
笔试回调服务以考生为维度进行回调,回调的信息为考生信息、考生的考试信息等信息。
回调地址为业务方在调用添加考生接口(POST /papers/{paperId}/test_user)中传入的callback参数。
回调类型、回调时机与回调配置
下面这些回调类型需要在调用创建考生接口时,添加callback
参数配置回调地址即可订阅一个考生下列回调类型的回调。
考生手动交卷或考试时间截止自动交卷
作弊检测完成
牛客后台完成了对考生的作弊检测
如果存在作弊重判,可能触发多次回调
人工判题完成
牛客系统中有用户对考生进行了人工判题
仅对开启人工判题的试卷有效
考生被删除
在牛客系统或通过API删除了某个考生
只允许考前删除考生,不涉及成绩报告相关数据
附件上传结束
到了试卷设置附件上传截止时间或这期间的每天0点
仅对考后仍允许上传附件的试卷有效
下面这些回调类型需要联系牛客开发人员。进行配置
非长期有效试卷考试结束
成绩报告变化
考生成绩报告发生变化
如果无特殊要求,建议回调接收方按“可重入”的思路进行方案设计,默认以最新1次的回调结果为准。
回调参数
通用回调参数
完成考试
、作弊检测
、人工判题
、考试结束
和成绩报告变化
这几种回调类型采用的时通用的回调参数。
考生删除
、链接过期
等回调事件,不涉及成绩报告相关信息。
callbackType
笔试场景下的回调类型:1.人工判题完成,3.完成考试,4.考试结束,5.成绩报告变化,6.作弊检测完成,8.考生被删除。 AI面试场景下的回调类型:201. 候选人被删除, 202. ai面试结束, 203. ai面试判题完成, 204. ai面试pdf报告生成完毕。使用建议:非特殊需要,不建议客户方对callbackType进行任何判断,牛客成绩报告默认均以最后1次回调为准,客户方客户保证回调操作可重入/覆盖式更新即可
testId
String
测评id唯一标识(String类型),对应到添加考生接口返回的考生实体中的testId字段
numTestId
测评id唯一标识(long类型),对应到添加考生接口返回的考生实体中的id字段
String
业务侧用户唯一标识,对应到考生实体的userKey字段
status
String
测评的状态 NOT_DO-未做题,DOING-正在做题,DONE-做完题,JUDGED-人工阅卷完成, CHEAT_DETECT_DONE-作弊检测完成,DELETE-删除
cheatStatus
作弊检测状态 作弊检测未完成(0), 作弊(1), 未作弊(2), 作弊疑似(3)
cheatReasonList
String
以文字表述的作弊原因字符串数组,具体格式为json中的string array转换出来的字符串。具体信息见链接,有值示例:["摄像头监控异常"],无值示例:[]
testStartTime
考生开始考试时间(豪秒级)
testFinishTime
考生交卷时间(豪秒级)
headUrl
String
考生自拍头像链接
score
float
考生试卷总得分(%.1f),笔试场景默认为必传,AI面试场景可能为null
scoreLeverType
取值:0表示百分制形式;1表示5星形式;
scoreLever
float
取值定义由scoreLeverType控制,当ScoreLeverType=0时,取值为score(%0.1f)字段值;当scoreLeverType=1时,取值为0.0,0.5,1.0,1.5,...,4.5,5.0,分别对应到5星档位;
testResult
String
表示考试结果,取值passed表示“通过”,failed表示“不通过”
rejectionReasons
String
表示筛选不通过的原因(仅在testResult="failed"时有效);原因存在多项时,采用";"进行拼接;没值时用null表示
specialNotes
String
表示报告中需要特别关注的事情;存在多个关注事项时,采用";"进行拼接;没值时用null表示
isFinalScore
boolean
是否是用户的最终成绩
moduleScores
List[String]
表示考生按能力项维度聚合的得分情况。这个参数会有多个,每一个的参数格式是moduleScore|moduleName
如 "70.5|英语能力
",moduleScore为skillScore的上级维度
moduleScoreLevers
List[String]
表示考生按能力项维度聚合的得分等级情况。这个参数会有多个,每一个的参数格式是moduleScoreLever|moduleName
如 "3.5|英语能力
",其中的moduleName与moduleScores中的moduleName一一对应
skillScores
List[String]
表示考生按技能项维度聚合的得分情况。这个参数会有多个,每一个的参数格式是skillScore|skillName
如 "60.5|抗压能力
",skillScore为moduleScore的下级维度
skillScoreLevers
List[String]
表示考生按技能项维度聚合的得分等级情况。这个参数会有多个,每一个的参数格式是skillScoreLever|skillName
如 "4.0|抗压能力
",其中的skillName与skillScores中的skillName一一对应
categoryScores
List[String]
表示考生按试卷目录维度聚合的得分情况。这个参数会有多个,每一个的参数格式是score|categoryId|categoryName
如1.5|100|
选择题。笔试场景默认为必传,AI面试场景为空
extDataItems
List[String]
可扩展的信息维度。这个参数会有多个,每一个的参数格式是json string。结构:{"id": "xx", "name": "xxx", "value": "xxx"}
例子:{"name":"不通过原因","id":"rejectionReasons","value":"候选人放弃面试"}
考生排名,这个排名是在回调的时间点计算出来
isCheated
boolean
true、false 是否作弊,疑似作弊时为null(待废弃,以cheatStatus字段为准)
resultPdfUrl
String
测评成绩报告的PDF版本的URL,支持按需配置
onlineTestResultUrl
String
测评成绩报告的网页版本的URL,支持按需配置
paperName
String
paperId
paperScore
试卷满分,笔试和试卷中的题目总分有关,ai面试默认100分
needJudge
boolean
试卷是否需要人工判题,true表示需要,false不表示不需要
isArchived
boolean
代表当前考生是否可以归档,true表示可以归档,false表示还不能归档(该标识仅代表系统判定考生分数不再改变,但是可能存在手动修改考生成绩以及多次重新判题修改分数的情况)
基于数据安全等方面考虑,resultPdfUrl
字段返回的pdf成绩报告地址,在2021年7月1日之后将启用基于tokenValue的校验、过期机制。
报告将会6个月之后过期(从回调时间点开始计算时间)。过期时间可登录牛客网企业版,
点击`设置->安全设置`来修改。更新设置将会对新生成的报告生效。
public class Main {
@Test
public void escapeOnlineTestResultUrl() throws UnsupportedEncodingException {
String onlineTestResultUrl = "https://dhr.nowcoder.com/console?theme=tinyLeft&access_token=1b60b47668a2459416985edfb4c4a2207cf318999c51715e00f722fd235b0b0b#paper/{\"tab\":\"index\",\"action\":\"candidate/result/index\",\"testId\":1837423}";
int anchorIndex = onlineTestResultUrl.indexOf("#paper/");
int encodeStrStartIndex = anchorIndex + "#paper/".length();
String anchorStr = StringUtils.substring(onlineTestResultUrl, encodeStrStartIndex);
String encodedAnchorStr = URLEncoder.encode(anchorStr, "UTF-8");
System.out.println(onlineTestResultUrl.substring(0, encodeStrStartIndex) + encodedAnchorStr);
onlineTestResultUrl
字段在url编码、解码过程中会出现部分字符转义失败的问题,在使用时需要按照Java
示例代码中的形式处理。
这个排名是在回调的时间点计算出来的,如果想实时获取最新排名,请调用查询单个考生考试结果接口
或获取所有测评信息接口。
isFinalScore
在考生测评无需人工判题、需要人工判题的题目没有作答或者需要人工判题的题目已经判题完成时为true。
但由于目前牛客系统中可以对已经判题的考生重新判题,因此该字段为true时不代表分数不会发生变化。
isCheated
字段在疑似作弊时为null。后续可能使用新的字段表示:作弊、疑似作弊、没有作弊的情况。
考生被删除
考试被删除时,只会回传考生的信息,具体参数如下:
status
测评的状态,在考生删除时为:DELETE(删除)
paperId
paperName
唯一确定一个用户的字符串
除了这些字段外,还会带上创建考生时填入的其他字段比如:phone
、email
等字段。更多考生个人信息字段详见:添加考生接口
笔试-免登录判题
无需登录系统,开放给第三方的判题能力,该接口可获取判题链接,判题链接会失效过期,无需保存,需要时实时获取即可
GET /judging-tests/quick-judge-url
paperId
userKey
String
考试编号,对应添加考生接口中key字段值
免登录判题短链
注意:链接有效期默认是2个月,从第一次请求接口生成时算起;同一个考生判题链接只会生成一次重复请求接口返回的是同一个判题链接
@Test
public void testGetProjects() {
String path = "/user/interview-projects/all";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/user/interview-projects/[email protected]' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : [ {
"id" : 1638,
"name" : "小程序测试",
"remark" : "",
"jobNums" : 2,
"studentNums" : 32,
"roundNums" : 5,
"status" : 1,
"type" : 0,
"star" : 1,
}, {
"id" : 1746,
"name" : "小程序",
"remark" : "",
"jobNums" : 10,
"studentNums" : 88,
"roundNums" : 4,
"status" : 0,
"type" : 0,
"star" : 1,
}, {
"id" : 1291,
"name" : "liumeng测试",
"remark" : "liumeng 测试",
"jobNums" : 30,
"studentNums" : 357,
"roundNums" : 14,
"status" : 0,
"type" : 0,
"star" : 0,
}, {
"id" : 1293,
"name" : "测试",
"remark" : "呵呵呵",
"jobNums" : 15,
"studentNums" : 130,
"roundNums" : 8,
"status" : 0,
"type" : 0,
"star" : 0,
GET /user/interview-projects/all
array
面试项目数组,关键信息见面试项目关键返回字段
面试-面试管理
面试实体关键字段
interviewProjectId
面试项目id
intervieweeName
String
面试者(候选人)姓名
intervieweeEmail
String
面试者(候选人)的邮箱
intervieweePhone
String
面试者(候选人)的手机
jobType
技术or非技术, 1技术面试、2非技术面试
String
deliverId
String
resumeUrl
String
用户简历地址
testResultUrl
String
round
当前处于第几轮
rounds
array
轮次实体关键字段
interviewReportUrl
String
面试报告地址
startTime
毫秒级时间戳、面试开始时间,即第一轮面试开始时间
expireTime
毫秒级时间戳、过期时间,到达过期时间且面试未使用过会标记为过期并且退费
elapsedTime
使用时长,单位毫秒
validTime
总的可用时长,单位是秒, 如果为0则默认为3小时。使用时长超过可用时长后面试房间会无法使用,除非延长面试
interviewerUrl
String
面试官面试地址
interviewerOfflineUrl
String
面试官线下面试地址, 只有开启了线下面试权限才能使用
intervieweeUrl
String
候选人面试地址
status
状态,0表示正常,1表示删除,2表示过期。
请不要根据elapsedTime
和validTime
判断面试是否超时,或者根据expireTime判断面试是否过期。牛客内部可能有优化策略,
如果需要判断请调用该接口获取面试房间状态
轮次实体关键字段
interviewId
round
第几轮面试
bookTime
预约时间、毫秒级时间戳
multi
是否多对一面试,0一对一面试,1多对一面试
offline
是否线下面试, 0线上,1线下
interviewerName
String
一对一面试字段,面试官姓名
interviewerPhone
String
一对一面试字段,面试官电话
interviewerEmail
String
一对一面试字段,面试官邮箱
userList
array
多对一面试字段,面试官实体关键字段
score
面试评分,0未评分, 1-2未通过,3-5通过
evaluation
String
elapsedTime
该轮使用时长,单位毫秒
intervieweeImage
String
候选人面试过程中的一张照片
status
轮次状态,0未开始、1进行中、3结束、4删除、5暂停、7面试淘汰被自动取消
面试官实体关键字段
interviewId
roundId
round
第几轮面试
String
面试官姓名
phone
String
面试官电话
email
String
面试官邮箱
是否主持人,0非主持人,1主持人
evaluation
String
elapsedTime
面试官面试时长, 单位毫秒, 非实时更新
status
状态, 0初始、1删除、2面试中、4结束
一对一面试轮次中,轮次实体字段的userList
会为空,多对一面试轮次中,
轮次实体字段的interviewerName、interviewerPhone、interviewerEmail
优先检查服务对应可用次数,当可用次数不够时使用账户余额进行检查
public class Main {
@Test
public void testCheckBalance() {
String path = "/interviews/checkBalance";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("techCount", 10);
mvMap.put("unTechCount", 10);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/interviews/[email protected]&unTechCount=10&techCount=10' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : {
"hostId" : 30,
"adminHrId" : 30,
"moneyEnough" : true,
"subAccountLimitEnough" : true
GET /interviews/checkBalance
techCount
技术类面试数量
unTechCount
非技术类面试数量
copilotFlag
boolean
是否开启智能面试(同时对techCount和unTechCount生效),不传默认是false
hostId
当前账号id
adminHrId
当前账号的公司主账号id
moneyEnough
boolean
公司主账号的余额是否充足
subAccountLimitEnough
boolean
子账号分配的业务额度是否充足
该接口协议由于协议复杂,扩展困难等问题,将不再添加新功能,且不支持最新的功能。请尽量使用新接口创建面试-新版
public class Main {
@Test
public void testCreateInterview(){
String path = "/interviews";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("projectId", 2071);
mvMap.put("intervieweeName", "nowcoder");
mvMap.put("intervieweeEmail", "[email protected]");
mvMap.put("intervieweePhone", "10000000000");
mvMap.put("copilotFlag", false);
mvMap.put("job", "java");
mvMap.put("jobType", 1);
mvMap.put("jobDesc", "职业介绍");
mvMap.put("deliverId", "TD6879239819");
mvMap.put("resumeUrl", "https://www.nowcoder.com");
mvMap.put("resumeText", "简历文本内容");
mvMap.put("testResultUrl", "https://www.nowcoder.com");
mvMap.put("rounds", "2021-08-26 11:00:00|coder|10000000000|[email protected]|0|0");
mvMap.put("rounds", "2021-08-26 11:30:00|-|-|-|0|1");
mvMap.put("multiUsers", "2|0|coder1|[email protected]|10000000001|1");
mvMap.put("multiUsers", "2|0|coder2|[email protected]|10000000002|0");
mvMap.put("callback", null);
mvMap.put("callback2", null);
mvMap.put("finishRedirectUrl", "https://www.nowcoder.com");
mvMap.put("finishRedirectUrls", "https://www.nowcoder.com");
mvMap.put("finishRedirectUrls", "https://www.nowcoder.com");
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "POST");
System.out.println(responseString);
curl --location --request POST 'https://dapi.nowcoder.com/v1/interviews' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com&intervieweeName=nowcoder&multiUsers=2%7C0%7Ccoder1%7Cer1%40nowcoder.com%7C10000000001%7C1&multiUsers=2%7C0%7Ccoder2%7Cer2%40nowcoder.com%7C10000000002%7C0&finishRedirectUrl=https%3A%2F%2Fwww.nowcoder.com&intervieweePhone=10000000000&deliverId=TD6879239819&intervieweeEmail=ee%40nowcoder.com&resumeUrl=https%3A%2F%2Fwww.nowcoder.com&testResultUrl=https%3A%2F%2Fwww.nowcoder.com&job=java&jobType=1&projectId=2071&rounds=2021-08-26+11%3A00%3A00%7Ccoder%7C10000000000%7Cer%40nowcoder.com%7C0%7C0&rounds=2021-08-26+11%3A30%3A00%7C-%7C-%7C-%7C0%7C1&finishRedirectUrls=https%3A%2F%2Fwww.nowcoder.com&finishRedirectUrls=https%3A%2F%2Fwww.nowcoder.com'
"code" : 0,
"msg" : "OK",
"data" : {
"id" : 36724903,
"interviewProjectId" : 2071,
"intervieweeName" : "nowcoder",
"intervieweeEmail" : "[email protected]",
"intervieweePhone" : "10000000000",
"jobType" : 1,
"job" : "java",
"deliverId" : "TD6879239819",
"resumeUrl" : "https://www.nowcoder.com",
"testResultUrl" : "https://www.nowcoder.com",
"round" : 0,
"rounds" : [ {
"id" : 289423,
"interviewId" : 36724903,
"round" : 1,
"bookTime" : 1629946800000,
"multi" : 0,
"offline" : 0,
"interviewerName" : "coder",
"interviewerPhone" : "10000000000",
"interviewerEmail" : "[email protected]",
"userList" : null,
"score" : 0,
"evaluation" : null,
"elapsedTime" : 0,
"status" : 0,
}, {
"id" : 289424,
"interviewId" : 36724903,
"round" : 2,
"bookTime" : 1629948600000,
"multi" : 1,
"offline" : 0,
"interviewerName" : null,
"interviewerPhone" : null,
"interviewerEmail" : null,
"userList" : [{
"id" : 186503,
"interviewId" : 36724903,
"roundId" : 289424,
"round" : 2,
"name" : "coder1",
"email" : "[email protected]",
"phone" : "10000000001",
"host" : 1,
"evaluation" : null,
"elapsedTime" : 0,
"status" : 0
}, {
"id" : 186504,
"interviewId" : 36724903,
"roundId" : 289424,
"round" : 2,
"name" : "coder2",
"email" : "[email protected]",
"phone" : "10000000002",
"host" : 0,
"evaluation" : null,
"elapsedTime" : 0,
"status" : 0
"score" : 0,
"evaluation" : null,
"elapsedTime" : 0,
"status" : 0
"interviewReportUrl" : "https://dapi.nowcoder.com/v1/interview-report/712E34F318A80DEC5D2B1AAD67C4DCC3/report_pdf?code=NstxvwnE",
"startTime" : null,
"expireTime" : 1635072309584,
"elapsedTime" : 0,
"validTime" : 0,
"interviewerUrl" : "https://examd.nowcoder.com/interview/36724903/interviewer?code=NstxvwnE",
"interviewerOfflineUrl" : "https://examd.nowcoder.com/interview/36724903/offline?code=NstxvwnE",
"intervieweeUrl" : "https://examd.nowcoder.com/interview/36724903/interviewee?code=WNDyBdkI",
"status" : 0
POST /interviews
projectId
所属项目id
intervieweeName
String
面试者的姓名
intervieweeEmail
String
面试者email
intervieweePhone
String
面试者手机号码
copilotFlag
boolean
非必填(默认false)
是否开启智能面试
String
面试职位名称
jobType
职位类型1-技术,2-非技术
jobDesc
String
非必填(长度上限4K)
deliverId
String
resumeUrl
String
简历URL
resumeText
String
非必填(长度上限12K)
简历文本内容
testResultUrl
String
笔试结果URL
rounds
array
轮次信息字符串
multiUsers
array
多对一面试必填(一对一面试非必填)
多对一面试字段,面试官信息字符串
callback
String
非必填(想使用对应回调功能必填)
面试轮次评价回调, 录音完成回调
callback2
String
非必填(想使用对应回调功能必填)
面试状态回调
finishRedirectUrl
String
非必填(想使用对应回调功能必填)
面试结束后跳转链接,一般用于三方对接填写面试评价使用, 搭配评分接口使用
finishRedirectUrls
array
非必填(想使用对应回调功能必填)
面试结束后跳转链接,一般用于三方对接填写面试评价使用, 搭配评分接口使用,这里适用于每一轮都需要不同的跳转链接,大小必须和rounds参数一样
public void testUpdateInterview(){
long interviewId = 36724903;
String path = String.format("/interviews/%d/interview", interviewId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("intervieweeName", "javaCoder");
mvMap.put("intervieweeEmail", "[email protected]");
mvMap.put("intervieweePhone", "10000000000");
mvMap.put("job", "java");
mvMap.put("jobType", 1);
mvMap.put("deliverId", "TD6879239819");
mvMap.put("resumeUrl", "https://www.nowcoder.com");
mvMap.put("testResultUrl", "https://www.nowcoder.com");
mvMap.put("rounds", "289423|2021-08-26 11:00:00|coder|10000000000|[email protected]|0|0");
mvMap.put("rounds", "289424|2021-08-26 11:30:00|-|-|-|0|1");
mvMap.put("multiUsers", "186503|2|0|coder1|[email protected]|10000000001|1");
mvMap.put("multiUsers", "186504|2|0|coder2|[email protected]|10000000002|0");
mvMap.put("callback", null);
mvMap.put("callback2", null);
mvMap.put("finishRedirectUrl", "https://www.nowcoder.com");
mvMap.put("finishRedirectUrls", "https://www.nowcoder.com");
mvMap.put("finishRedirectUrls", "https://www.nowcoder.com");
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "PUT");
System.out.println(responseString);
curl --location --request PUT 'https://dapi.nowcoder.com/v1/interviews/36724903/interview' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com&intervieweeName=javaCoder&multiUsers=186503%7C2%7C0%7Ccoder1%7Cer1%40nowcoder.com%7C10000000001%7C1&multiUsers=186504%7C2%7C0%7Ccoder2%7Cer2%40nowcoder.com%7C10000000002%7C0&finishRedirectUrl=https%3A%2F%2Fwww.nowcoder.com&intervieweePhone=10000000000&deliverId=TD6879239819&intervieweeEmail=java%40nowcoder.com&resumeUrl=https%3A%2F%2Fwww.nowcoder.com&testResultUrl=https%3A%2F%2Fwww.nowcoder.com&job=java&jobType=1&rounds=289423%7C2021-08-26+11%3A00%3A00%7Ccoder%7C10000000000%7Cer%40nowcoder.com%7C0%7C0&rounds=289424%7C2021-08-26+11%3A30%3A00%7C-%7C-%7C-%7C0%7C1&finishRedirectUrls=https%3A%2F%2Fwww.nowcoder.com&finishRedirectUrls=https%3A%2F%2Fwww.nowcoder.com'
"code" : 0,
"msg" : "OK",
"data" : {
"id" : 36724903,
"interviewProjectId" : 2071,
"intervieweeName" : "javaCoder",
"intervieweeEmail" : "[email protected]",
"intervieweePhone" : "10000000000",
"jobType" : 1,
"job" : "java",
"deliverId" : "TD6879239819",
"resumeUrl" : "https://www.nowcoder.com",
"testResultUrl" : "https://www.nowcoder.com",
"round" : 0,
"rounds" : [ {
"id" : 289423,
"interviewId" : 36724903,
"round" : 1,
"bookTime" : 1629946800000,
"multi" : 0,
"offline" : 0,
"interviewerName" : "coder",
"interviewerPhone" : "10000000000",
"interviewerEmail" : "[email protected]",
"userList" : null,
"score" : 0,
"evaluation" : null,
"elapsedTime" : 0,
"status" : 0
}, {
"id" : 289424,
"interviewId" : 36724903,
"round" : 2,
"bookTime" : 1629948600000,
"multi" : 1,
"offline" : 0,
"interviewerName" : null,
"interviewerPhone" : null,
"interviewerEmail" : null,
"userList" : [{
"id" : 186503,
"interviewId" : 36724903,
"roundId" : 289424,
"round" : 2,
"name" : "coder1",
"email" : "[email protected]",
"phone" : "10000000001",
"host" : 1,
"evaluation" : null,
"elapsedTime" : 0,
"status" : 0
}, {
"id" : 186504,
"interviewId" : 36724903,
"roundId" : 289424,
"round" : 2,
"name" : "coder2",
"email" : "[email protected]",
"phone" : "10000000002",
"host" : 0,
"evaluation" : null,
"elapsedTime" : 0,
"status" : 0
"score" : 0,
"evaluation" : null,
"elapsedTime" : 0,
"status" : 0
"interviewReportUrl" : "https://dapi.nowcoder.com/v1/interview-report/712E34F318A80DEC5D2B1AAD67C4DCC3/report_pdf?code=NstxvwnE",
"startTime" : null,
"expireTime" : 1635072309584,
"elapsedTime" : 0,
"validTime" : 0,
"interviewerUrl" : "https://examd.nowcoder.com/interview/36724903/interviewer?code=NstxvwnE",
"interviewerOfflineUrl" : "https://examd.nowcoder.com/interview/36724903/offline?code=NstxvwnE",
"intervieweeUrl" : "https://examd.nowcoder.com/interview/36724903/interviewee?code=WNDyBdkI",
"status" : 0
PUT /interviews/{id:[0-9]+}/interview
intervieweeName
String
面试者的姓名
intervieweeEmail
String
面试者email
intervieweePhone
String
面试者手机号码
String
面试职位名称
jobType
职位类型1-技术,2-非技术
deliverId
String
resumeUrl
String
简历URL
testResultUrl
String
笔试结果URL
rounds
array
轮次信息字符串
multiUsers
array
多对一面试必填
多对一面试字段,面试官信息字符串
finishRedirectUrl
String
面试结束后跳转链接,用于三方对接填写面试评价使用
轮次参数字段
bookTime
String/long
预约时间, yyyy-MM-dd HH:mm:ss 或者 毫秒级时间戳
interviewerName
String
一对一面试字段,面试官姓名
interviewerPhone
String
一对一面试字段,面试官号码
interviewerEmail
String
一对一面试字段,面试官邮箱
offline
0线上、1线下
multi
0一对一面试、1多对一面试
使用时按照列表顺序以'|'为分割符拼接起来,为空的参数可以用'-'替代
面试官参数字段
面试官id
round
第几轮的面试官
String
面试官姓名
email
String
面试官邮箱
phone
String
面试官号码
0非主持人、1主持人
使用时按照列表顺序以'|'为分割符拼接起来,为空的参数可以用'-'替代
id
大于0则代表是修改操作,等于0则代表是新增操作。
轮次采用增量更新,只能进行修改和新增。但在多对一面试的面试官信息更新中采用全量更新,即没有传递的面试官会被删除。
取消一轮面试
public class Main {
@Test
public void testCancelInterviewRound(){
long interviewId = 36724903;
long roundId = 289424;
String path = String.format("/interviews/%d/%d", interviewId, roundId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("cancelCurrentRoundOnly", true);
mvMap.put("needSendCancelNotice", false);
mvMap.put("cancelReason", "test");
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "DELETE");
System.out.println(responseString);
curl --location --request DELETE 'https://dapi.nowcoder.com/v1/interviews/36724903/289424' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com&needSendCancelNotice=false&cancelCurrentRoundOnly=true&cancelReason=test'
"code" : 0,
"msg" : "OK",
"data" : null
DELETE /interviews/{id:[0-9]+}/{roundId:[0-9]+}
roundId
面试轮次id
cancelCurrentRoundOnly
boolean
必填(默认为false)
是否只取消当前轮次而保留后面轮次
needSendCancelNotice
boolean
必填(默认为false)
是否发送取消通知
cancelReason
String
public void testGetById() {
long interviewId = 36724903;
String path = String.format("/interviews/%d", interviewId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/interviews/[email protected]' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : {
"id" : 36724903,
"interviewProjectId" : 2071,
"intervieweeName" : "javaCoder",
"intervieweeEmail" : "[email protected]",
"intervieweePhone" : "10000000000",
"jobType" : 1,
"job" : "java",
"deliverId" : "TD6879239819",
"resumeUrl" : "https://www.nowcoder.com",
"testResultUrl" : "https://www.nowcoder.com",
"round" : 0,
"rounds" : [{
"id" : 289423,
"interviewId" : 36724903,
"round" : 1,
"bookTime" : 1629946800000,
"multi" : 0,
"offline" : 0,
"interviewerName" : "coder",
"interviewerPhone" : "10000000000",
"interviewerEmail" : "[email protected]",
"userList" : null,
"score" : 0,
"evaluation" : null,
"elapsedTime" : 0,
"status" : 0,
"interviewReportUrl" : "https://dapi.nowcoder.com/v1/interview-report/712E34F318A80DEC5D2B1AAD67C4DCC3/report_pdf?code=NstxvwnE",
"startTime" : null,
"expireTime" : 1635072309584,
"elapsedTime" : 0,
"validTime" : 0,
"interviewerUrl" : "https://examd.nowcoder.com/interview/36724903/interviewer?code=NstxvwnE",
"interviewerOfflineUrl" : "https://examd.nowcoder.com/interview/36724903/offline?code=NstxvwnE",
"intervieweeUrl" : "https://examd.nowcoder.com/interview/36724903/interviewee?code=WNDyBdkI",
"status" : 0
GET /interviews/{id:[0-9]+}
面试房间id
获取面试房间状态
public class Main {
@Test
public void testGetRoomStatus() {
String path = "/interviews/room-status";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("roomId", 36724903);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/interviews/[email protected]&roomId=36724903' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : {
"roomId" : 36724903,
"timeRunOut" : false,
"roomStatus" : 0,
"remainMinitus" : 180
GET /interviews/room-status
roomId
roomId
timeRunOut
boolean
面试是否已经超时
roomStatus
房间状态:0-正常,1-取消,2-过期
remainMinitus
剩余可用时长,单位:分钟. validTime - elapsedTime
批量获取面试官、候选人在线状态
public class Main {
@Test
public void testGetPersonStatus() {
String path = "/interviews/rooms-status";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("roomIdList", 36724903);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/interviews/[email protected]&roomIdList=36724903' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : [ {
"roomId" : 36724903,
"intervieweeStatus" : 0,
"interviewerStatus" : 0
GET /interviews/rooms-status
roomIdList
array
面试id数组
roomId
intervieweeStatus
候选人在线状态:0-离线, 1-在线
interviewerStatus
面试官在线状态:0-离线, 1-在线
当面试的超时导致面试无法使用时,可以通过该接口延长可用时长,每次调用会延长一次初始时长,但会收取一次费用。
public class Main {
@Test
public void testExtendInterview() {
long interviewId = 36724903;
String path = String.format("/interviews/%d/extend", interviewId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "PUT");
System.out.println(responseString);
curl --location --request PUT 'https://dapi.nowcoder.com/v1/interviews/36724903/extend' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com'
"code" : 0,
"msg" : "OK",
"data" : null
PUT /interviews/{id:[0-9]+}/extend
如果面试未结束时调用该接口会缓存结果,等结束面试时进行覆盖
public class Main {
@Test
public void testInterviewEvaluation() {
String path = "/user/interviews-other/round/evaluations";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("version", 1);
mvMap.put("roundId", 289423);
mvMap.put("interviewId", 36724903);
mvMap.put("roundIdx", 1);
mvMap.put("isPass", true);
String responseString = NowcoderApiRequestUtils.request(path, mvMap, "PUT");
System.out.println(responseString);
curl --location --request PUT 'https://dapi.nowcoder.com/v1/user/interviews-other/round/evaluations' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--data-raw 'api_key=huaxinjiayou%40126.com&interviewId=36724903&roundIdx=1&isPass=true&version=1&roundId=289423'
"code" : 0,
"msg" : "OK",
"data" : { }
PUT /user/interviews-other/round/evaluations
version
固定值 1
roundId
interviewId
roundIdx
isPass
空json串
ai智能报告点赞点踩
/v1/partners/interview/report/prefer
请求方法和类型
post, application/json
url后面添加api_key的query参数,如:/v1/partners/interview/report/prefer?api_key=xxx
请求添加一个Authorization头,值为:Bearer token,这个token可以从hr系统获得
请求和回报参数见右边
请求参数:
"roundId": "面试轮次id,long",
"sceneType": "场景类型,int:1.报告点赞,2.报告点踩,3.评价维度点赞,4.评价维度点踩,5.答题分析点赞,6.答题分析点踩",
"sceneId": "场景id,string:sceneType=1,2时不传;sceneType=3,4时,代表dimensionId;sceneType=5,6时,代表analysisId"
回包参数:
"code": "int:0表示成功,非0表示失败",
"msg": "string:code非0时表示报错原因"
面试-新版面试管理
旧版接口使用form格式参数,组装复杂,扩展困难。因此对创建面试、修改面试两个接口进行了重写,采用json格式参数。请尽量切换到新版接口,旧版接口将不再增加新特性。
Content-Type
统一使用application/json
如果参数的非空校验、格式校验等基础校验失败,Response Status
会返回400。其他情况Response Status
统一使用200,返回值中code
为0代表成功,其他代表失败
面试实体字段
interviewId
expireTime
秒级时间戳,过期失效时间
validDuration
interviewReportUrl
String
面试报告地址
interviewRounds
array
@Test
public void testNewCreateInterview(){
String path = "/partners/interview/create_interview";
PartnerInterviewDTO partnerInterviewDTO = new PartnerInterviewDTO();
PartnerInterviewDTO.OrgInfo orgInfo = new PartnerInterviewDTO.OrgInfo();
orgInfo.projectId = 2071L;
orgInfo.deptId = null;
PartnerInterviewDTO.Interviewee interviewee = new PartnerInterviewDTO.Interviewee();
interviewee.name = "coder";
interviewee.email = "[email protected]";
interviewee.phone = "10000000000";
interviewee.resumeUrl = "https://www.nowcoder.com";
PartnerInterviewDTO.JobInfo jobInfo = new PartnerInterviewDTO.JobInfo();
jobInfo.jobName = "java";
jobInfo.deliverId = "TD12983710892";
List<PartnerInterviewDTO.InterviewRound> interviewRounds = new ArrayList<>();
PartnerInterviewDTO.InterviewRound interviewRound = new PartnerInterviewDTO.InterviewRound();
interviewRound.offline = 0;
interviewRound.interviewType = 1;
interviewRound.panelFlag = 0;
interviewRound.bookTime = 1629982394L;
interviewRounds.add(interviewRound);
List<PartnerInterviewDTO.Interviewer> interviewers = new ArrayList<>();
PartnerInterviewDTO.Interviewer interviewer = new PartnerInterviewDTO.Interviewer();
interviewer.name = "er";
interviewer.email = "[email protected]";
interviewer.phone = "10000000000";
interviewer.host = 1;
interviewers.add(interviewer);
interviewRound.interviewers = interviewers;
partnerInterviewDTO.interviewee = interviewee;
partnerInterviewDTO.jobInfo = jobInfo;
partnerInterviewDTO.interviewRounds = interviewRounds;
partnerInterviewDTO.orgInfo = orgInfo;
String response = NowcoderApiRequestUtils.jsonRequest(path, partnerInterviewDTO, "POST");
System.out.println(response);
curl --location --request POST 'https://dapi.nowcoder.com/v1/partners/interview/[email protected]' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--header 'Content-Type: application/json' \
--data-raw '{"interviewRounds":[{"bookTime":1629982394,"interviewType":1,"interviewers":[{"email":"[email protected]","host":1,"name":"er","phone":"10000000000"}],"offline":0,"panelFlag":0}],"interviewee":{"email":"[email protected]","name":"coder","phone":"10000000000","resumeUrl":"https://www.nowcoder.com"},"jobInfo":{"deliverId":"TD12983710892","jobName":"java"},"orgInfo":{"projectId":2071}}'
"code" : 0,
"msg" : "OK",
"data" : {
"interviewId" : 37000637,
"expireTime" : 1635080281,
"validDuration" : 10800,
"interviewReportUrl" : "https://dapi.nowcoder.com/v1/interview-report/844C0F4B8BD9E8685D2B1AAD67C4DCC3/report_pdf?code=QQGnFJCH",
"interviewRounds" : [ {
"roundId" : 289426,
"roundIdx" : 1,
"offline" : 0,
"panelFlag" : 0,
"bookTime" : 1629982394,
"interviewer" : [ {
"interviewerId" : null,
"name" : "er",
"email" : "[email protected]",
"phone" : "10000000000",
"host" : 1,
"interviewUrl" : "https://examd.nowcoder.com/interview/37000637/interviewer?code=QQGnFJCH"
} ],
"interviewee" : {
"name" : "coder",
"email" : "[email protected]",
"phone" : "10000000000",
"interviewUrl" : "https://examd.nowcoder.com/interview/37000637/interviewee?code=SSEb3BCn"
"interviewType" : 1
POST /partners/interview/create_interview
Content-type
application/json
orgInfo
interviewee
候选人信息
jobInfo
interviewRounds
array
callback
projectId
面试所属项目id
deptId
面试所属部门id
copilotFlag
boolean
非必填(默认false)
是否开启智能面试
resumeText
String
非必填(长度上限12K)
简历文本内容
候选人信息
String
候选人姓名
email
String
候选人邮箱
phone
String
候选人电话
resumeUrl
String
候选人简历地址
deliverId
String
投递编号, 同一个面试项目下唯一
jobName
String
应聘岗位名称
offline
线上视频 或 线下面试, 0表示线上视频,1表示线下面试
interviewType
技术面试 或 非技术面试, 1表示技术面试,2表示非技术面试
panelFlag
1对1面试 或 多对1面试, 0表示1对1面试,1表示多对1面试
bookTime
面试预约时间, 秒级时间戳
redirectUrl
非必填, 一对一面试用到
重定向链接
interviewers
array
面试官信息
面试官信息
String
面试官姓名
email
String
面试官邮箱
phone
String
面试官电话
是否主持人 0代表非主持人, 1代表主持人
feedbackCb
String
非必填, 多对一面试用到
自定义面评表地址, https格式。
redirectUrl
非必填, 多对一面试用到
重定向链接
重定向链接
finishRedirectUrl
String
结束时的重定向链接
@Test
public void testNewUpdateInterview(){
String path = "/partners/interview/part-update-interview";
PartnerInterviewDTO partnerInterviewDTO = new PartnerInterviewDTO();
PartnerInterviewDTO.OrgInfo orgInfo = new PartnerInterviewDTO.OrgInfo();
orgInfo.deptId = null;
PartnerInterviewDTO.Interviewee interviewee = new PartnerInterviewDTO.Interviewee();
interviewee.name = "coder5";
partnerInterviewDTO.interviewId = 37000637L;
partnerInterviewDTO.interviewee = interviewee;
String response = NowcoderApiRequestUtils.jsonRequest(path, partnerInterviewDTO, "POST");
System.out.println(response);
curl --location --request POST 'https://dapi.nowcoder.com/v1/partners/interview/[email protected]' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--header 'Content-Type: application/json' \
--data-raw '{"interviewId":37000637,"interviewee":{"name":"coder5"}}'
"code" : 0,
"msg" : "OK",
"data" : {
"interviewId" : 37000637,
"expireTime" : 1856005081,
"validDuration" : 10800,
"interviewReportUrl" : "https://dapi.nowcoder.com/v1/interview-report/844C0F4B8BD9E8685D2B1AAD67C4DCC3/report_pdf?code=QQGnFJCH",
"interviewRounds" : [ {
"roundId" : 289426,
"roundIdx" : 1,
"offline" : 0,
"panelFlag" : 0,
"bookTime" : 1629982394,
"interviewer" : [ {
"interviewerId" : null,
"name" : "er",
"email" : "[email protected]",
"phone" : "10000000000",
"host" : 1,
"interviewUrl" : "https://examd.nowcoder.com/interview/37000637/interviewer?code=QQGnFJCH"
} ],
"interviewee" : {
"name" : "coder5",
"email" : "[email protected]",
"phone" : "10000000000",
"interviewUrl" : "https://examd.nowcoder.com/interview/37000637/interviewee?code=SSEb3BCn"
"interviewType" : 1
}, {
"roundId" : 289428,
"roundIdx" : 2,
"offline" : 0,
"panelFlag" : 0,
"bookTime" : 1656322593,
"interviewer" : [ {
"interviewerId" : null,
"name" : null,
"email" : null,
"phone" : "14700000000",
"host" : 1,
"interviewUrl" : "https://examd.nowcoder.com/interview/37000637/interviewer?code=QQGnFJCH"
} ],
"interviewee" : {
"name" : "coder5",
"email" : "[email protected]",
"phone" : "10000000000",
"interviewUrl" : "https://examd.nowcoder.com/interview/37000637/interviewee?code=SSEb3BCn"
"interviewType" : 1
POST /partners/interview/part-update-interview
Content-type
application/json
interviewId
orgInfo
interviewee
候选人信息
jobInfo
interviewRounds
array
deptId
面试所属部门id
候选人信息
String
候选人姓名
email
String
候选人邮箱
phone
String
候选人电话
resumeUrl
String
候选人简历地址
deliverId
String
投递编号,同一个面试项目下唯一
jobName
String
应聘岗位名称
roundId
需要修改轮次时填写
需要修改的轮次id,新增时不填
offline
线上视频 或 线下面试, 0表示线上视频,1表示线下面试, 必填
interviewType
技术面试 或 非技术面试, 1表示技术面试,2表示非技术面试, 必填
panelFlag
1对1面试 或 多对1面试, 0表示1对1面试,1表示多对1面试, 必填
bookTime
面试预约时间, 秒级时间戳, 必填
redirectUrl
非必填, 一对一面试用到
重定向链接
interviewers
array
面试官信息
面试官信息
interviewerId
多对一面试修改面试官填写
面试官id,多对一面试修改时传入
String
面试官姓名, 必填
email
String
面试官邮箱
phone
String
面试官电话
是否主持人 0代表非主持人, 1代表主持人 必填
delete
boolean
非必填,默认false
是否删除面试官,多对一时用到
feedbackCb
String
非必填,多对一面试用到
自定义面评表地址, https格式
redirectUrl
非必填,多对一面试用到
重定向链接
重定向链接
finishRedirectUrl
String
结束时的重定向链接
@Test
public void testNewUpdateInterview(){
String path = "/partners/interview/update_interview";
PartnerInterviewDTO partnerInterviewDTO = new PartnerInterviewDTO();
PartnerInterviewDTO.OrgInfo orgInfo = new PartnerInterviewDTO.OrgInfo();
orgInfo.deptId = null;
PartnerInterviewDTO.Interviewee interviewee = new PartnerInterviewDTO.Interviewee();
interviewee.name = "coder2";
interviewee.email = "[email protected]";
interviewee.phone = "10000000000";
interviewee.resumeUrl = "https://www.nowcoder.com";
PartnerInterviewDTO.JobInfo jobInfo = new PartnerInterviewDTO.JobInfo();
jobInfo.jobName = "java";
jobInfo.deliverId = "TD12983710892";
List<PartnerInterviewDTO.InterviewRound> interviewRounds = new ArrayList<>();
PartnerInterviewDTO.InterviewRound interviewRound = new PartnerInterviewDTO.InterviewRound();
interviewRound.roundId = 289426L;
interviewRound.offline = 0;
interviewRound.interviewType = 1;
interviewRound.panelFlag = 0;
interviewRound.bookTime = 1629982394L;
interviewRounds.add(interviewRound);
List<PartnerInterviewDTO.Interviewer> interviewers = new ArrayList<>();
PartnerInterviewDTO.Interviewer interviewer = new PartnerInterviewDTO.Interviewer();
interviewer.name = "er";
interviewer.email = "[email protected]";
interviewer.phone = "10000000000";
interviewer.host = 1;
interviewers.add(interviewer);
interviewRound.interviewers = interviewers;
partnerInterviewDTO.interviewId = 37000637L;
partnerInterviewDTO.interviewee = interviewee;
partnerInterviewDTO.jobInfo = jobInfo;
partnerInterviewDTO.interviewRounds = interviewRounds;
partnerInterviewDTO.orgInfo = orgInfo;
String response = NowcoderApiRequestUtils.jsonRequest(path, partnerInterviewDTO, "POST");
System.out.println(response);
curl --location --request POST 'https://dapi.nowcoder.com/v1/partners/interview/[email protected]' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c' \
--header 'Content-Type: application/json' \
--data-raw '{"interviewId":37000637,"interviewRounds":[{"bookTime":1629982394,"interviewType":1,"interviewers":[{"email":"[email protected]","host":1,"name":"er","phone":"10000000000"}],"offline":0,"panelFlag":0,"roundId":289426}],"interviewee":{"email":"[email protected]","name":"coder2","phone":"10000000000","resumeUrl":"https://www.nowcoder.com"},"jobInfo":{"deliverId":"TD12983710892","jobName":"java"},"orgInfo":{}}'
"code" : 0,
"msg" : "OK",
"data" : {
"interviewId" : 37000637,
"expireTime" : 1635080281,
"validDuration" : 10800,
"interviewReportUrl" : "https://dapi.nowcoder.com/v1/interview-report/844C0F4B8BD9E8685D2B1AAD67C4DCC3/report_pdf?code=QQGnFJCH",
"interviewRounds" : [ {
"roundId" : 289426,
"roundIdx" : 1,
"offline" : 0,
"panelFlag" : 0,
"bookTime" : 1629982394,
"interviewer" : [ {
"interviewerId" : null,
"name" : "er",
"email" : "[email protected]",
"phone" : "10000000000",
"host" : 1,
"interviewUrl" : "https://examd.nowcoder.com/interview/37000637/interviewer?code=QQGnFJCH"
} ],
"interviewee" : {
"name" : "coder2",
"email" : "[email protected]",
"phone" : "10000000000",
"interviewUrl" : "https://examd.nowcoder.com/interview/37000637/interviewee?code=SSEb3BCn"
"interviewType" : 1
POST /partners/interview/update_interview
Content-type
application/json
interviewId
orgInfo
interviewee
候选人信息
jobInfo
interviewRounds
array
deptId
面试所属部门id
候选人信息
String
候选人姓名
email
String
候选人邮箱
phone
String
候选人电话
resumeUrl
String
候选人简历地址
deliverId
String
投递编号,同一个面试项目下唯一
jobName
String
应聘岗位名称
roundId
修改轮次信息时必填,增加轮次时不填
需要修改的轮次id
offline
线上视频 或 线下面试, 0表示线上视频,1表示线下面试, 必填
interviewType
技术面试 或 非技术面试, 1表示技术面试,2表示非技术面试, 必填
panelFlag
1对1面试 或 多对1面试, 0表示1对1面试,1表示多对1面试, 必填
bookTime
面试预约时间, 秒级时间戳, 必填
redirectUrl
非必填, 一对一面试用到
重定向链接
interviewers
array
面试官信息
面试官信息
interviewerId
多对一面试修改必填
面试官id,多对一面试修改时传入
String
面试官姓名, 必填
email
String
面试官邮箱
phone
String
面试官电话
是否主持人 0代表非主持人, 1代表主持人 必填
feedbackCb
String
非必填, 多对一面试用到
自定义面评表地址, https格式
redirectUrl
非必填,多对一面试用到
重定向链接
重定向链接
finishRedirectUrl
String
结束时的重定向链接
String interviewId = "31310396";
String path = String.format("/partners/interview/get-record-url/%s", interviewId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = CommonUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'https://dapi.nowcoder.com/v1/partners/interview/get-record-url?interviewId=31310396&[email protected]' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c1273a4e338f650a5c'
"code": 0,
"msg": "OK",
"data": {
"interviewId": 31310396,
"roundRecordDatas": [
"roundId": 430801,
"round": 1,
"roundStatus": 3,
"recordUrl": null,
"recordExpireTime": null
"roundId": 430802,
"round": 2,
"roundStatus": 3,
"recordUrl": null,
"recordExpireTime": null
GET /partners/interview/get-record-url
Content-type
application/json
interviewId
面试房间id
interviewId
面试房间id
roundRecordDatas
array
录音数组,关键信息见录音信息实体
录音实体字段
rounId
round
roundStatus
轮次状态,0未开始、1进行中、3结束、4删除、5暂停、7面试淘汰被自动取消
recordUrl
String
录音下载链接 (不存在返回null)
recordExpireTime
下载链接过期时间(注意是秒级时间戳,不存在返回null)
面试-回调服务
面试轮次评价回调
每一轮面试结束时进行回调
轮次评分修改分数后进行回调
interviewId
roundId
面试轮次id
round
score
0未评分、1-2淘汰、3-5通过
evaluation
String
reportUrl
Stirng
deliverId
String
interviewerName
String
面试官姓名,以最后评价填写的为准
roundStatus
固定值3,代表面试结束
roundStartTime
该轮面试开始时间
roundEndTime
该轮面试结束时间
roundElapsedTime
String
该轮使用时长,单位毫秒
autoCancelRounds
array
自动取消轮次信息,如果开启了淘汰取消后续轮次这里会携带被自动取消的轮次信息
interviewerEvaluations
array
多对一面试非主持人评价信息
自动取消轮次信息
round
第几轮, 被折叠的轮次也会记录
多对一面试非主持人评价信息
interviewerName
String
面试官姓名
interviewerEvaluations
String
面试官评价
面试状态回调
面试开始使用
面试删除、过期
候选人或面试官上线
interviewId
status
状态, 1取消、2过期、3开始使用、4面试官或候选人上线
收到该回调表示面试轮次ai智能报告已经生成,相关答题分析和面试记录可以通过下面两个接口来拉取
请求方法和类型
post, application/x-www-form-urlencoded
string
string
加密后的内容
string
回调的数据,是个json字符串,结构见右边
回调参数中data对应的json结构:
"interviewId": "面试id,long",
"roundId": "面试轮次id,long",
"round": "表示第几轮,int",
回包参数:
"code": "int:200表示成功,非200表示失败",
"message": "string:表示失败时的报错原因"
答题分析获取接口
接口地址
/v1/partners/interview/report/answer-analysis
请求方法和类型
url后面添加api_key的query参数,如:/v1/partners/interview/answer-analysis?api_key=xxx
请求添加一个Authorization头,值为:"Bearer token",其中的token可以从hr系统获得
请求query参数
roundId
必填,轮次id
回包参数见右边
{
"code": "int:0表示成功,非0表示失败",
"msg": "string:code非0时表示报错原因",
"data": {
"assessmentDimensionList": [
"name": "维度名称,string:学习能力",
"assessment": "维度评价内容,string:候选人应对挫折和卡点,容易陷入自我怀疑与否定...",
"dimensionId": "维度评价id,string:249483jsfjoe"
"answerAnalysisList": [
"chatList": [
"roleType": "角色类型,int: 0.面试官,1.候选人",
"roleName": "角色名称,string:面试官",
"content": "对话的内容,string:请你做个自我介绍"
"skills": [
"考察技能名称,string:Java"
"advice": "答题分析建议,string:候选人回答基本正确,但掌握比较基础,建议深入考核",
"analysisId": "答题分析建议id,string:2898598543jfosdjfoi"
面试记录获取接口
接口地址
/v1/partners/interview/report/chat-list
请求方法和类型
url后面添加api_key的query参数,如:/v1/partners/interview/chat-list?api_key=xxx
请求添加一个Authorization头,值为:"Bearer token",其中的token可以从hr系统获得
请求query参数
roundId
必填,轮次id
curPage
选填,请求页,默认值1
pageSize
选填,每页大小,默认值20
回包参数见右边
{
"code": "int:0表示成功,非0表示失败",
"msg": "string:code非0时表示报错原因",
"data": {
"totalCount": "int: 总条数",
"totalPage": "int:总页数",
"curPage": "int:当前页",
"pageSize": "int:当前每页大小",
"originChatList": [
"roleType": "角色类型,int: 0.面试官,1.候选人",
"roleName": "角色名称,string:比如面试官",
"content": "对话的内容,string:请你做个自我介绍",
"actionTime": "对话时间戳,long:毫秒时间戳"
系统接口
获取用户当前账户信息
public class Main {
@Test
public void testGetUserTestInfo() {
String path = "/users/self";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = CommonUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'http://localhost:8888/v1/users/[email protected]' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : {
"id" : 30,
"email" : "[email protected]",
"phone" : null,
"companyName" : "华鑫加油",
"headUrl" : null,
"accountConfig" : null,
"validBeginTime" : null,
"validEndTime" : null,
"encryptPassword" : null
查询当前用户的账户信息
GET /users/self
email
账号登录邮箱
phone
companyName
公司名称,不同于账号名称
headUrl
validBeginTime
有效期开始时间
validEndTime
有效期开始时间
encryptPassword
获取hr系统每种服务的最大可用额度
public class Main {
@Test
public void testGetPaperTestsInfo() {
String path = "/user/checkBalance/count";
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
mvMap.put("serviceTypes", 1);
mvMap.put("serviceTypes", 3);
mvMap.put("serviceTypes", 7);
mvMap.put("serviceTypes", 8);
mvMap.put("serviceTypes", 9);
String responseString = CommonUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'http://localhost:8888/v1/user/checkBalance/[email protected]&serviceTypes=1&serviceTypes=3&serviceTypes=7&serviceTypes=8&serviceTypes=9' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : {
"hostId" : 30,
"adminHrId" : 30,
"techContestCount" : 2176,
"untechContestCount" : 4352,
"techInterviewCount" : 932,
"untechInterviewCount" : 1865,
"extendPackageCount" : 3264
查询每个服务类型最大可以使用的额度(包括额度和账户余额),包括技术笔试、非技术笔试、技术面试、非技术面试、面试扩展包。
最大可以使用额度计算方式:
技术笔试额度=合同剩余技术笔试额度+取整(账户余额/30)
非技术笔试额度=合同剩余非技术笔试额度+取整(账户余额/15)
技术面试额度=合同剩余技术面试额度+取整(账户余额/70)
非技术面试额度=合同剩余非技术笔试额度+取整(账户余额/35)
面试扩展包=合同剩余扩展包额度+取整(账户余额/20)
注:子账号查询,返回总账号/子账号的额度限制,取最小值
支持指定类型查询最大额度,例如 只查询笔试的;也可以支持不指定类型,查询全部最大额度;
GET /user/checkBalance/count
serviceTypes
需要查询的服务类型,可以传多个值。1:技术面试,3:技术笔试,7:非技术面试,8:非技术笔试,9:面试扩展包
hostId
当前用户ID
adminHrId
用户主账号ID,如果当前用户为主账号与用户ID相同
techContestCount
技术笔试可用额度,-1为无限制
untechContestCount
非技术笔试可用额度,-1为无限制
techInterviewCount
技术面试可用额度,-1为无限制
untechInterviewCount
非技术面试可用额度,-1为无限制
extendPackageCount
面试扩展包可用额度,-1为无限制,子账户此项默认返回父账可用最大额度
获取异步任务进度
public class Main {
@Test
public void testGetJobProcess() {
String processId = "LntWBG4tD1YRyJ4z7woVSqaU5sxulx36";
String path = String.format("/job-progress/%s", processId);
MultiValuedMap<String, Object> mvMap = new ArrayListValuedHashMap<>();
String responseString = CommonUtils.request(path, mvMap, "GET");
System.out.println(responseString);
curl --location --request GET 'http://localhost:8888/v1/job-progress/[email protected]' \
--header 'Authorization: Bearer 9e906c093a59bc80e312d2821d5daff81aa9c7a8512638f4c73a4e338f650a5c'
"code" : 0,
"msg" : "OK",
"data" : {
"ownerId" : 0,
"content" : "",
"end" : true,
"error" : false,
"type" : 2,
"progress" : 100,
"jobId" : "LntWBG4tD1YRyJ4z7woVSqaU5sxulx36",
"jobInfo" : null
获取异步任务进度
GET /job-progress/{id}
异步任务id
ownerId
jobId
异步任务id
progress
异步任务进度,0~100之间的整数
异步任务是否结束。true结束、false未结束
error
异步任务是否发生异常。true发生了异常、false未发生异常
content
异步任务返回信息
content字段的类型,1-下载链接 2-文字结果 3-JSON字符串
英姿勃勃的黄豆 · 科兴股权大战迎尾声,创始人获刑 | 南方周末 6 月前 |