新增v2特征,评分接口;数据过滤
This commit is contained in:
parent
9e0729f6f5
commit
849ebe8f4d
|
|
@ -1,5 +1,6 @@
|
||||||
package com.lyxh.api.docking.controller.ftapi;
|
package com.lyxh.api.docking.controller.ftapi;
|
||||||
|
|
||||||
|
import com.lyxh.api.docking.enums.ResultFilterType;
|
||||||
import com.lyxh.api.docking.model.ftapi.PaymentProfileRequest;
|
import com.lyxh.api.docking.model.ftapi.PaymentProfileRequest;
|
||||||
import com.lyxh.api.docking.model.ftapi.PaymentProfileResponse;
|
import com.lyxh.api.docking.model.ftapi.PaymentProfileResponse;
|
||||||
import com.lyxh.api.docking.service.PaymentProfileService;
|
import com.lyxh.api.docking.service.PaymentProfileService;
|
||||||
|
|
@ -20,14 +21,37 @@ public class FortispayController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private PaymentProfileService paymentProfileService;
|
private PaymentProfileService paymentProfileService;
|
||||||
|
|
||||||
/** 印尼支付行为画像 - v1 */
|
/** 印尼支付行为画像 - V1 特征 */
|
||||||
@PostMapping("/payment-feature")
|
@PostMapping("/payment-feature")
|
||||||
public ResponseEntity<PaymentProfileResponse> getPaymentFeature(
|
public ResponseEntity<PaymentProfileResponse> getPaymentFeature(
|
||||||
@Valid @RequestBody PaymentProfileRequest request,
|
@Valid @RequestBody PaymentProfileRequest request,
|
||||||
@RequestHeader(value = "X-Request-Id", required = false) String xRequestId,
|
@RequestHeader(value = "X-Request-Id", required = false) String xRequestId,
|
||||||
@RequestHeader(value = "X-Language", required = false) String language) {
|
@RequestHeader(value = "X-Language", required = false) String language) {
|
||||||
|
return executeQuery(request, xRequestId, language, ResultFilterType.V1_FEATURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 印尼支付行为画像 - V2 特征(除综合评分外的全量 V2.2 字段) */
|
||||||
|
@PostMapping("/payment-feature-v2")
|
||||||
|
public ResponseEntity<PaymentProfileResponse> getPaymentFeatureV2(
|
||||||
|
@Valid @RequestBody PaymentProfileRequest request,
|
||||||
|
@RequestHeader(value = "X-Request-Id", required = false) String xRequestId,
|
||||||
|
@RequestHeader(value = "X-Language", required = false) String language) {
|
||||||
|
return executeQuery(request, xRequestId, language, ResultFilterType.V2_FEATURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 印尼支付行为画像 - V2 综合评分 */
|
||||||
|
@PostMapping("/payment-feature-v2-score")
|
||||||
|
public ResponseEntity<PaymentProfileResponse> getPaymentFeatureV2Score(
|
||||||
|
@Valid @RequestBody PaymentProfileRequest request,
|
||||||
|
@RequestHeader(value = "X-Request-Id", required = false) String xRequestId,
|
||||||
|
@RequestHeader(value = "X-Language", required = false) String language) {
|
||||||
|
return executeQuery(request, xRequestId, language, ResultFilterType.V2_SCORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseEntity<PaymentProfileResponse> executeQuery(
|
||||||
|
PaymentProfileRequest request, String xRequestId, String language, ResultFilterType filterType) {
|
||||||
String weOrderNo = UUID.randomUUID().toString().replace("-", "");
|
String weOrderNo = UUID.randomUUID().toString().replace("-", "");
|
||||||
PaymentProfileResponse body = paymentProfileService.query(request, xRequestId, language, weOrderNo);
|
PaymentProfileResponse body = paymentProfileService.query(request, xRequestId, language, weOrderNo, filterType);
|
||||||
ResponseEntity.BodyBuilder builder = ResponseEntity.ok()
|
ResponseEntity.BodyBuilder builder = ResponseEntity.ok()
|
||||||
.header("X-Request-Id", xRequestId != null ? xRequestId : weOrderNo);
|
.header("X-Request-Id", xRequestId != null ? xRequestId : weOrderNo);
|
||||||
if (body.getResponseId() != null && !body.getResponseId().isEmpty()) {
|
if (body.getResponseId() != null && !body.getResponseId().isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.lyxh.api.docking.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* result 字段过滤模式
|
||||||
|
*/
|
||||||
|
public enum ResultFilterType {
|
||||||
|
/** 只保留 V1.xlsx 的字段(536 字段,6 模块) */
|
||||||
|
V1_FEATURE,
|
||||||
|
/** 保留 V2.2.xlsx 的特征字段(606 字段,6 模块,排除 overall_score) */
|
||||||
|
V2_FEATURE,
|
||||||
|
/** 只保留 V2.2.xlsx 的 overall_score 字段(15 字段,1 模块) */
|
||||||
|
V2_SCORE
|
||||||
|
}
|
||||||
|
|
@ -4,10 +4,12 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.lyxh.api.docking.enums.ApiType;
|
import com.lyxh.api.docking.enums.ApiType;
|
||||||
|
import com.lyxh.api.docking.enums.ResultFilterType;
|
||||||
import com.lyxh.api.docking.exception.ApiCallException;
|
import com.lyxh.api.docking.exception.ApiCallException;
|
||||||
import com.lyxh.api.docking.model.ftapi.FortispayRequest;
|
import com.lyxh.api.docking.model.ftapi.FortispayRequest;
|
||||||
import com.lyxh.api.docking.model.ftapi.PaymentProfileRequest;
|
import com.lyxh.api.docking.model.ftapi.PaymentProfileRequest;
|
||||||
import com.lyxh.api.docking.model.ftapi.PaymentProfileResponse;
|
import com.lyxh.api.docking.model.ftapi.PaymentProfileResponse;
|
||||||
|
import com.lyxh.api.docking.util.ResultFieldFilter;
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
@ -35,7 +37,7 @@ public class PaymentProfileService {
|
||||||
private ObjectMapper objectMapper;
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
public PaymentProfileResponse query(PaymentProfileRequest request, String xRequestId, String language,
|
public PaymentProfileResponse query(PaymentProfileRequest request, String xRequestId, String language,
|
||||||
String weOrderNo) {
|
String weOrderNo, ResultFilterType filterType) {
|
||||||
boolean isEncrypted = request.getEncryptAlgo() != null && !request.getEncryptAlgo().isBlank();
|
boolean isEncrypted = request.getEncryptAlgo() != null && !request.getEncryptAlgo().isBlank();
|
||||||
String idCardForCache = isEncrypted ? request.getIdCard() : DigestUtils.md5Hex(request.getIdCard());
|
String idCardForCache = isEncrypted ? request.getIdCard() : DigestUtils.md5Hex(request.getIdCard());
|
||||||
String mobileForCache = isEncrypted ? request.getMobile() : DigestUtils.md5Hex(request.getMobile());
|
String mobileForCache = isEncrypted ? request.getMobile() : DigestUtils.md5Hex(request.getMobile());
|
||||||
|
|
@ -67,7 +69,7 @@ public class PaymentProfileService {
|
||||||
this::shouldCache
|
this::shouldCache
|
||||||
);
|
);
|
||||||
JsonNode root = objectMapper.readTree(respJson);
|
JsonNode root = objectMapper.readTree(respJson);
|
||||||
return parseResponse(root);
|
return parseResponse(root, filterType);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new ApiCallException("PARSE_ERROR", "Failed to parse Fortispay response: " + e.getMessage(), null);
|
throw new ApiCallException("PARSE_ERROR", "Failed to parse Fortispay response: " + e.getMessage(), null);
|
||||||
} catch (ApiCallException e) {
|
} catch (ApiCallException e) {
|
||||||
|
|
@ -103,7 +105,7 @@ public class PaymentProfileService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PaymentProfileResponse parseResponse(JsonNode node) {
|
private PaymentProfileResponse parseResponse(JsonNode node, ResultFilterType filterType) {
|
||||||
PaymentProfileResponse response = new PaymentProfileResponse();
|
PaymentProfileResponse response = new PaymentProfileResponse();
|
||||||
response.setCode(node.path("code").asText());
|
response.setCode(node.path("code").asText());
|
||||||
response.setMessage(node.path("message").asText());
|
response.setMessage(node.path("message").asText());
|
||||||
|
|
@ -119,6 +121,7 @@ public class PaymentProfileService {
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, Object> resultMap = objectMapper.convertValue(result, Map.class);
|
Map<String, Object> resultMap = objectMapper.convertValue(result, Map.class);
|
||||||
|
ResultFieldFilter.filter(resultMap, filterType);
|
||||||
dataNode.setResult(resultMap);
|
dataNode.setResult(resultMap);
|
||||||
}
|
}
|
||||||
response.setData(dataNode);
|
response.setData(dataNode);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,301 @@
|
||||||
|
package com.lyxh.api.docking.util;
|
||||||
|
|
||||||
|
import com.lyxh.api.docking.enums.ResultFilterType;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付行为画像 result 字段过滤器
|
||||||
|
* 根据 富通数据服务接口数据字典 提取 V1/V2.2 字段白名单
|
||||||
|
*/
|
||||||
|
public final class ResultFieldFilter {
|
||||||
|
|
||||||
|
private static final Map<String, Set<String>> V1_WHITELIST = Map.of(
|
||||||
|
"app_behavior", Set.of(
|
||||||
|
"apply_cnt_day3", "apply_cnt_day7", "apply_cnt_day14", "apply_cnt_day30",
|
||||||
|
"apply_cnt_day60", "apply_cnt_day90", "apply_cnt_day180", "apply_cnt_day240",
|
||||||
|
"apply_cnt_day365", "apply_cnt_day730",
|
||||||
|
"apply_org_cnt_day3", "apply_org_cnt_day7", "apply_org_cnt_day14", "apply_org_cnt_day30",
|
||||||
|
"apply_org_cnt_day60", "apply_org_cnt_day90", "apply_org_cnt_day180", "apply_org_cnt_day240",
|
||||||
|
"apply_org_cnt_day365", "apply_org_cnt_day730",
|
||||||
|
"apply_daily_max_cnt_day3", "apply_daily_max_cnt_day7", "apply_daily_max_cnt_day14", "apply_daily_max_cnt_day30",
|
||||||
|
"apply_daily_max_cnt_day60", "apply_daily_max_cnt_day90", "apply_daily_max_cnt_day180", "apply_daily_max_cnt_day240",
|
||||||
|
"apply_daily_max_cnt_day365", "apply_daily_max_cnt_day730",
|
||||||
|
"apply_daily_max_org_cnt_day3", "apply_daily_max_org_cnt_day7", "apply_daily_max_org_cnt_day14", "apply_daily_max_org_cnt_day30",
|
||||||
|
"apply_daily_max_org_cnt_day60", "apply_daily_max_org_cnt_day90", "apply_daily_max_org_cnt_day180", "apply_daily_max_org_cnt_day240",
|
||||||
|
"apply_daily_max_org_cnt_day365", "apply_daily_max_org_cnt_day730",
|
||||||
|
"apply_has_record_day_cnt_day3", "apply_has_record_day_cnt_day7", "apply_has_record_day_cnt_day14", "apply_has_record_day_cnt_day30",
|
||||||
|
"apply_has_record_day_cnt_day60", "apply_has_record_day_cnt_day90", "apply_has_record_day_cnt_day180", "apply_has_record_day_cnt_day240",
|
||||||
|
"apply_has_record_day_cnt_day365", "apply_has_record_day_cnt_day730",
|
||||||
|
"apply_max_org_cnt_rate_day3", "apply_max_org_cnt_rate_day7", "apply_max_org_cnt_rate_day14", "apply_max_org_cnt_rate_day30",
|
||||||
|
"apply_max_org_cnt_rate_day60", "apply_max_org_cnt_rate_day90", "apply_max_org_cnt_rate_day180", "apply_max_org_cnt_rate_day240",
|
||||||
|
"apply_max_org_cnt_rate_day365", "apply_max_org_cnt_rate_day730",
|
||||||
|
"apply_mean_delta_day3", "apply_mean_delta_day7", "apply_mean_delta_day14", "apply_mean_delta_day30",
|
||||||
|
"apply_mean_delta_day60", "apply_mean_delta_day90", "apply_mean_delta_day180", "apply_mean_delta_day240",
|
||||||
|
"apply_mean_delta_day365", "apply_mean_delta_day730",
|
||||||
|
"apply_max_delta_day3", "apply_max_delta_day7", "apply_max_delta_day14", "apply_max_delta_day30",
|
||||||
|
"apply_max_delta_day60", "apply_max_delta_day90", "apply_max_delta_day180", "apply_max_delta_day240",
|
||||||
|
"apply_max_delta_day365", "apply_max_delta_day730",
|
||||||
|
"apply_min_delta_day3", "apply_min_delta_day7", "apply_min_delta_day14", "apply_min_delta_day30",
|
||||||
|
"apply_min_delta_day60", "apply_min_delta_day90", "apply_min_delta_day180", "apply_min_delta_day240",
|
||||||
|
"apply_min_delta_day365", "apply_min_delta_day730"
|
||||||
|
),
|
||||||
|
"loan_behavior", Set.of(
|
||||||
|
"credit_cnt_day3", "credit_cnt_day7", "credit_cnt_day14", "credit_cnt_day30",
|
||||||
|
"credit_cnt_day60", "credit_cnt_day90", "credit_cnt_day180", "credit_cnt_day240",
|
||||||
|
"credit_cnt_day365", "credit_cnt_day730",
|
||||||
|
"credit_org_cnt_day3", "credit_org_cnt_day7", "credit_org_cnt_day14", "credit_org_cnt_day30",
|
||||||
|
"credit_org_cnt_day60", "credit_org_cnt_day90", "credit_org_cnt_day180", "credit_org_cnt_day240",
|
||||||
|
"credit_org_cnt_day365", "credit_org_cnt_day730",
|
||||||
|
"credit_daily_max_cnt_day3", "credit_daily_max_cnt_day7", "credit_daily_max_cnt_day14", "credit_daily_max_cnt_day30",
|
||||||
|
"credit_daily_max_cnt_day60", "credit_daily_max_cnt_day90", "credit_daily_max_cnt_day180", "credit_daily_max_cnt_day240",
|
||||||
|
"credit_daily_max_cnt_day365", "credit_daily_max_cnt_day730",
|
||||||
|
"credit_daily_max_org_cnt_day3", "credit_daily_max_org_cnt_day7", "credit_daily_max_org_cnt_day14", "credit_daily_max_org_cnt_day30",
|
||||||
|
"credit_daily_max_org_cnt_day60", "credit_daily_max_org_cnt_day90", "credit_daily_max_org_cnt_day180", "credit_daily_max_org_cnt_day240",
|
||||||
|
"credit_daily_max_org_cnt_day365", "credit_daily_max_org_cnt_day730",
|
||||||
|
"credit_has_record_day_cnt_day3", "credit_has_record_day_cnt_day7", "credit_has_record_day_cnt_day14", "credit_has_record_day_cnt_day30",
|
||||||
|
"credit_has_record_day_cnt_day60", "credit_has_record_day_cnt_day90", "credit_has_record_day_cnt_day180", "credit_has_record_day_cnt_day240",
|
||||||
|
"credit_has_record_day_cnt_day365", "credit_has_record_day_cnt_day730",
|
||||||
|
"credit_max_org_cnt_rate_day3", "credit_max_org_cnt_rate_day7", "credit_max_org_cnt_rate_day14", "credit_max_org_cnt_rate_day30",
|
||||||
|
"credit_max_org_cnt_rate_day60", "credit_max_org_cnt_rate_day90", "credit_max_org_cnt_rate_day180", "credit_max_org_cnt_rate_day240",
|
||||||
|
"credit_max_org_cnt_rate_day365", "credit_max_org_cnt_rate_day730",
|
||||||
|
"credit_mean_delta_day3", "credit_mean_delta_day7", "credit_mean_delta_day14", "credit_mean_delta_day30",
|
||||||
|
"credit_mean_delta_day60", "credit_mean_delta_day90", "credit_mean_delta_day180", "credit_mean_delta_day240",
|
||||||
|
"credit_mean_delta_day365", "credit_mean_delta_day730",
|
||||||
|
"credit_max_delta_day3", "credit_max_delta_day7", "credit_max_delta_day14", "credit_max_delta_day30",
|
||||||
|
"credit_max_delta_day60", "credit_max_delta_day90", "credit_max_delta_day180", "credit_max_delta_day240",
|
||||||
|
"credit_max_delta_day365", "credit_max_delta_day730",
|
||||||
|
"credit_min_delta_day3", "credit_min_delta_day7", "credit_min_delta_day14", "credit_min_delta_day30",
|
||||||
|
"credit_min_delta_day60", "credit_min_delta_day90", "credit_min_delta_day180", "credit_min_delta_day240",
|
||||||
|
"credit_min_delta_day365", "credit_min_delta_day730",
|
||||||
|
"credit_total_amt_day3", "credit_total_amt_day7", "credit_total_amt_day14", "credit_total_amt_day30",
|
||||||
|
"credit_total_amt_day60", "credit_total_amt_day90", "credit_total_amt_day180", "credit_total_amt_day240",
|
||||||
|
"credit_total_amt_day365", "credit_total_amt_day730",
|
||||||
|
"credit_avg_amt_day3", "credit_avg_amt_day7", "credit_avg_amt_day14", "credit_avg_amt_day30",
|
||||||
|
"credit_avg_amt_day60", "credit_avg_amt_day90", "credit_avg_amt_day180", "credit_avg_amt_day240",
|
||||||
|
"credit_avg_amt_day365", "credit_avg_amt_day730",
|
||||||
|
"credit_min_amt_day3", "credit_min_amt_day7", "credit_min_amt_day14", "credit_min_amt_day30",
|
||||||
|
"credit_min_amt_day60", "credit_min_amt_day90", "credit_min_amt_day180", "credit_min_amt_day240",
|
||||||
|
"credit_min_amt_day365", "credit_min_amt_day730",
|
||||||
|
"credit_max_amt_day3", "credit_max_amt_day7", "credit_max_amt_day14", "credit_max_amt_day30",
|
||||||
|
"credit_max_amt_day60", "credit_max_amt_day90", "credit_max_amt_day180", "credit_max_amt_day240",
|
||||||
|
"credit_max_amt_day365", "credit_max_amt_day730",
|
||||||
|
"credit_pass_rate_day3", "credit_pass_rate_day7", "credit_pass_rate_day14", "credit_pass_rate_day30",
|
||||||
|
"credit_pass_rate_day60", "credit_pass_rate_day90", "credit_pass_rate_day180", "credit_pass_rate_day240",
|
||||||
|
"credit_pass_rate_day365", "credit_pass_rate_day730"
|
||||||
|
),
|
||||||
|
"repay_behavior", Set.of(
|
||||||
|
"repay_cnt_day3", "repay_cnt_day7", "repay_cnt_day14", "repay_cnt_day30",
|
||||||
|
"repay_cnt_day60", "repay_cnt_day90", "repay_cnt_day180", "repay_cnt_day240",
|
||||||
|
"repay_cnt_day365", "repay_cnt_day730",
|
||||||
|
"repay_org_cnt_day3", "repay_org_cnt_day7", "repay_org_cnt_day14", "repay_org_cnt_day30",
|
||||||
|
"repay_org_cnt_day60", "repay_org_cnt_day90", "repay_org_cnt_day180", "repay_org_cnt_day240",
|
||||||
|
"repay_org_cnt_day365", "repay_org_cnt_day730",
|
||||||
|
"repay_daily_max_cnt_day3", "repay_daily_max_cnt_day7", "repay_daily_max_cnt_day14", "repay_daily_max_cnt_day30",
|
||||||
|
"repay_daily_max_cnt_day60", "repay_daily_max_cnt_day90", "repay_daily_max_cnt_day180", "repay_daily_max_cnt_day240",
|
||||||
|
"repay_daily_max_cnt_day365", "repay_daily_max_cnt_day730",
|
||||||
|
"repay_daily_max_org_cnt_day3", "repay_daily_max_org_cnt_day7", "repay_daily_max_org_cnt_day14", "repay_daily_max_org_cnt_day30",
|
||||||
|
"repay_daily_max_org_cnt_day60", "repay_daily_max_org_cnt_day90", "repay_daily_max_org_cnt_day180", "repay_daily_max_org_cnt_day240",
|
||||||
|
"repay_daily_max_org_cnt_day365", "repay_daily_max_org_cnt_day730",
|
||||||
|
"repay_has_record_day_cnt_day3", "repay_has_record_day_cnt_day7", "repay_has_record_day_cnt_day14", "repay_has_record_day_cnt_day30",
|
||||||
|
"repay_has_record_day_cnt_day60", "repay_has_record_day_cnt_day90", "repay_has_record_day_cnt_day180", "repay_has_record_day_cnt_day240",
|
||||||
|
"repay_has_record_day_cnt_day365", "repay_has_record_day_cnt_day730",
|
||||||
|
"repay_max_org_cnt_rate_day3", "repay_max_org_cnt_rate_day7", "repay_max_org_cnt_rate_day14", "repay_max_org_cnt_rate_day30",
|
||||||
|
"repay_max_org_cnt_rate_day60", "repay_max_org_cnt_rate_day90", "repay_max_org_cnt_rate_day180", "repay_max_org_cnt_rate_day240",
|
||||||
|
"repay_max_org_cnt_rate_day365", "repay_max_org_cnt_rate_day730",
|
||||||
|
"repay_mean_delta_day3", "repay_mean_delta_day7", "repay_mean_delta_day14", "repay_mean_delta_day30",
|
||||||
|
"repay_mean_delta_day60", "repay_mean_delta_day90", "repay_mean_delta_day180", "repay_mean_delta_day240",
|
||||||
|
"repay_mean_delta_day365", "repay_mean_delta_day730",
|
||||||
|
"repay_max_delta_day3", "repay_max_delta_day7", "repay_max_delta_day14", "repay_max_delta_day30",
|
||||||
|
"repay_max_delta_day60", "repay_max_delta_day90", "repay_max_delta_day180", "repay_max_delta_day240",
|
||||||
|
"repay_max_delta_day365", "repay_max_delta_day730",
|
||||||
|
"repay_min_delta_day3", "repay_min_delta_day7", "repay_min_delta_day14", "repay_min_delta_day30",
|
||||||
|
"repay_min_delta_day60", "repay_min_delta_day90", "repay_min_delta_day180", "repay_min_delta_day240",
|
||||||
|
"repay_min_delta_day365", "repay_min_delta_day730",
|
||||||
|
"repay_total_amt_day3", "repay_total_amt_day7", "repay_total_amt_day14", "repay_total_amt_day30",
|
||||||
|
"repay_total_amt_day60", "repay_total_amt_day90", "repay_total_amt_day180", "repay_total_amt_day240",
|
||||||
|
"repay_total_amt_day365", "repay_total_amt_day730",
|
||||||
|
"repay_avg_amt_day3", "repay_avg_amt_day7", "repay_avg_amt_day14", "repay_avg_amt_day30",
|
||||||
|
"repay_avg_amt_day60", "repay_avg_amt_day90", "repay_avg_amt_day180", "repay_avg_amt_day240",
|
||||||
|
"repay_avg_amt_day365", "repay_avg_amt_day730",
|
||||||
|
"repay_min_amt_day3", "repay_min_amt_day7", "repay_min_amt_day14", "repay_min_amt_day30",
|
||||||
|
"repay_min_amt_day60", "repay_min_amt_day90", "repay_min_amt_day180", "repay_min_amt_day240",
|
||||||
|
"repay_min_amt_day365", "repay_min_amt_day730",
|
||||||
|
"repay_max_amt_day3", "repay_max_amt_day7", "repay_max_amt_day14", "repay_max_amt_day30",
|
||||||
|
"repay_max_amt_day60", "repay_max_amt_day90", "repay_max_amt_day180", "repay_max_amt_day240",
|
||||||
|
"repay_max_amt_day365", "repay_max_amt_day730",
|
||||||
|
"balance_amt_day3", "balance_amt_day7", "balance_amt_day14", "balance_amt_day30",
|
||||||
|
"balance_amt_day60", "balance_amt_day90", "balance_amt_day180", "balance_amt_day240",
|
||||||
|
"balance_amt_day365", "balance_amt_day730",
|
||||||
|
"balance_amt_rate_day3", "balance_amt_rate_day7", "balance_amt_rate_day14", "balance_amt_rate_day30",
|
||||||
|
"balance_amt_rate_day60", "balance_amt_rate_day90", "balance_amt_rate_day180", "balance_amt_rate_day240",
|
||||||
|
"balance_amt_rate_day365", "balance_amt_rate_day730"
|
||||||
|
),
|
||||||
|
"time_structure", Set.of(
|
||||||
|
"apply_days_since_last", "credit_days_since_last", "repay_days_since_last",
|
||||||
|
"apply_days_since_first", "credit_days_since_first", "repay_days_since_first",
|
||||||
|
"reject_cnt_day3", "reject_cnt_day7", "reject_cnt_day14", "reject_cnt_day30",
|
||||||
|
"reject_cnt_day60", "reject_cnt_day90", "reject_cnt_day180", "reject_cnt_day240",
|
||||||
|
"reject_cnt_day365", "reject_cnt_day730",
|
||||||
|
"reject_cnt_rate_day3", "reject_cnt_rate_day7", "reject_cnt_rate_day14", "reject_cnt_rate_day30",
|
||||||
|
"reject_cnt_rate_day60", "reject_cnt_rate_day90", "reject_cnt_rate_day180", "reject_cnt_rate_day240",
|
||||||
|
"reject_cnt_rate_day365", "reject_cnt_rate_day730",
|
||||||
|
"reject_org_cnt_day3", "reject_org_cnt_day7", "reject_org_cnt_day14", "reject_org_cnt_day30",
|
||||||
|
"reject_org_cnt_day60", "reject_org_cnt_day90", "reject_org_cnt_day180", "reject_org_cnt_day240",
|
||||||
|
"reject_org_cnt_day365", "reject_org_cnt_day730",
|
||||||
|
"reject_org_cnt_rate_day3", "reject_org_cnt_rate_day7", "reject_org_cnt_rate_day14", "reject_org_cnt_rate_day30",
|
||||||
|
"reject_org_cnt_rate_day60", "reject_org_cnt_rate_day90", "reject_org_cnt_rate_day180", "reject_org_cnt_rate_day240",
|
||||||
|
"reject_org_cnt_rate_day365", "reject_org_cnt_rate_day730"
|
||||||
|
),
|
||||||
|
"delinq_monitor", Set.of(
|
||||||
|
"overdue_org_cnt_day3", "overdue_org_cnt_day7", "overdue_org_cnt_day14", "overdue_org_cnt_day30",
|
||||||
|
"overdue_org_cnt_day60", "overdue_org_cnt_day90", "overdue_org_cnt_day180", "overdue_org_cnt_day240",
|
||||||
|
"overdue_org_cnt_day365", "overdue_org_cnt_day730",
|
||||||
|
"overdue_org_cnt_rate_day3", "overdue_org_cnt_rate_day7", "overdue_org_cnt_rate_day14", "overdue_org_cnt_rate_day30",
|
||||||
|
"overdue_org_cnt_rate_day60", "overdue_org_cnt_rate_day90", "overdue_org_cnt_rate_day180", "overdue_org_cnt_rate_day240",
|
||||||
|
"overdue_org_cnt_rate_day365", "overdue_org_cnt_rate_day730",
|
||||||
|
"overdue_failed_pay_cnt_day3", "overdue_failed_pay_cnt_day7", "overdue_failed_pay_cnt_day14", "overdue_failed_pay_cnt_day30",
|
||||||
|
"overdue_failed_pay_cnt_day60", "overdue_failed_pay_cnt_day90", "overdue_failed_pay_cnt_day180", "overdue_failed_pay_cnt_day240",
|
||||||
|
"overdue_failed_pay_cnt_day365", "overdue_failed_pay_cnt_day730",
|
||||||
|
"overdue_failed_pay_org_cnt_day3", "overdue_failed_pay_org_cnt_day7", "overdue_failed_pay_org_cnt_day14", "overdue_failed_pay_org_cnt_day30",
|
||||||
|
"overdue_failed_pay_org_cnt_day60", "overdue_failed_pay_org_cnt_day90", "overdue_failed_pay_org_cnt_day180", "overdue_failed_pay_org_cnt_day240",
|
||||||
|
"overdue_failed_pay_org_cnt_day365", "overdue_failed_pay_org_cnt_day730",
|
||||||
|
"overdue_failed_pay_org_cnt_rate_day3", "overdue_failed_pay_org_cnt_rate_day7", "overdue_failed_pay_org_cnt_rate_day14", "overdue_failed_pay_org_cnt_rate_day30",
|
||||||
|
"overdue_failed_pay_org_cnt_rate_day60", "overdue_failed_pay_org_cnt_rate_day90", "overdue_failed_pay_org_cnt_rate_day180", "overdue_failed_pay_org_cnt_rate_day240",
|
||||||
|
"overdue_failed_pay_org_cnt_rate_day365", "overdue_failed_pay_org_cnt_rate_day730"
|
||||||
|
),
|
||||||
|
"flow_anomaly", Set.of(
|
||||||
|
"same_day_pay_repay_cnt_day3", "same_day_pay_repay_cnt_day7", "same_day_pay_repay_cnt_day14", "same_day_pay_repay_cnt_day30",
|
||||||
|
"same_day_pay_repay_cnt_day60", "same_day_pay_repay_cnt_day90", "same_day_pay_repay_cnt_day180", "same_day_pay_repay_cnt_day240",
|
||||||
|
"same_day_pay_repay_cnt_day365", "same_day_pay_repay_cnt_day730",
|
||||||
|
"same_day_pay_repay_daynum_day3", "same_day_pay_repay_daynum_day7", "same_day_pay_repay_daynum_day14", "same_day_pay_repay_daynum_day30",
|
||||||
|
"same_day_pay_repay_daynum_day60", "same_day_pay_repay_daynum_day90", "same_day_pay_repay_daynum_day180", "same_day_pay_repay_daynum_day240",
|
||||||
|
"same_day_pay_repay_daynum_day365", "same_day_pay_repay_daynum_day730",
|
||||||
|
"same_day_pay_repay_rate_day3", "same_day_pay_repay_rate_day7", "same_day_pay_repay_rate_day14", "same_day_pay_repay_rate_day30",
|
||||||
|
"same_day_pay_repay_rate_day60", "same_day_pay_repay_rate_day90", "same_day_pay_repay_rate_day180", "same_day_pay_repay_rate_day240",
|
||||||
|
"same_day_pay_repay_rate_day365", "same_day_pay_repay_rate_day730",
|
||||||
|
"same_day_pay_repay_daynum_rate_day3", "same_day_pay_repay_daynum_rate_day7", "same_day_pay_repay_daynum_rate_day14", "same_day_pay_repay_daynum_rate_day30",
|
||||||
|
"same_day_pay_repay_daynum_rate_day60", "same_day_pay_repay_daynum_rate_day90", "same_day_pay_repay_daynum_rate_day180", "same_day_pay_repay_daynum_rate_day240",
|
||||||
|
"same_day_pay_repay_daynum_rate_day365", "same_day_pay_repay_daynum_rate_day730",
|
||||||
|
"same_day_pay_repay_amt_day3", "same_day_pay_repay_amt_day7", "same_day_pay_repay_amt_day14", "same_day_pay_repay_amt_day30",
|
||||||
|
"same_day_pay_repay_amt_day60", "same_day_pay_repay_amt_day90", "same_day_pay_repay_amt_day180", "same_day_pay_repay_amt_day240",
|
||||||
|
"same_day_pay_repay_amt_day365", "same_day_pay_repay_amt_day730",
|
||||||
|
"same_day_pay_repay_amt_rate_day3", "same_day_pay_repay_amt_rate_day7", "same_day_pay_repay_amt_rate_day14", "same_day_pay_repay_amt_rate_day30",
|
||||||
|
"same_day_pay_repay_amt_rate_day60", "same_day_pay_repay_amt_rate_day90", "same_day_pay_repay_amt_rate_day180", "same_day_pay_repay_amt_rate_day240",
|
||||||
|
"same_day_pay_repay_amt_rate_day365", "same_day_pay_repay_amt_rate_day730"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/** V2.2 相比 V1 新增的字段(不含 overall_score) */
|
||||||
|
private static final Map<String, Set<String>> V2_ADDITIONS = Map.of(
|
||||||
|
"loan_behavior", Set.of(
|
||||||
|
"credit_to_apply_rate_by_org_cnt_day3", "credit_to_apply_rate_by_org_cnt_day7",
|
||||||
|
"credit_to_apply_rate_by_org_cnt_day14", "credit_to_apply_rate_by_org_cnt_day30",
|
||||||
|
"credit_to_apply_rate_by_org_cnt_day60", "credit_to_apply_rate_by_org_cnt_day90",
|
||||||
|
"credit_to_apply_rate_by_org_cnt_day180", "credit_to_apply_rate_by_org_cnt_day240",
|
||||||
|
"credit_to_apply_rate_by_org_cnt_day365", "credit_to_apply_rate_by_org_cnt_day730"
|
||||||
|
),
|
||||||
|
"repay_behavior", Set.of(
|
||||||
|
"repay_to_credit_rate_by_cnt_day3", "repay_to_credit_rate_by_cnt_day7",
|
||||||
|
"repay_to_credit_rate_by_cnt_day14", "repay_to_credit_rate_by_cnt_day30",
|
||||||
|
"repay_to_credit_rate_by_cnt_day60", "repay_to_credit_rate_by_cnt_day90",
|
||||||
|
"repay_to_credit_rate_by_cnt_day180", "repay_to_credit_rate_by_cnt_day240",
|
||||||
|
"repay_to_credit_rate_by_cnt_day365", "repay_to_credit_rate_by_cnt_day730",
|
||||||
|
"repay_to_credit_rate_by_org_cnt_day3", "repay_to_credit_rate_by_org_cnt_day7",
|
||||||
|
"repay_to_credit_rate_by_org_cnt_day14", "repay_to_credit_rate_by_org_cnt_day30",
|
||||||
|
"repay_to_credit_rate_by_org_cnt_day60", "repay_to_credit_rate_by_org_cnt_day90",
|
||||||
|
"repay_to_credit_rate_by_org_cnt_day180", "repay_to_credit_rate_by_org_cnt_day240",
|
||||||
|
"repay_to_credit_rate_by_org_cnt_day365", "repay_to_credit_rate_by_org_cnt_day730",
|
||||||
|
"repay_to_apply_rate_by_cnt_day3", "repay_to_apply_rate_by_cnt_day7",
|
||||||
|
"repay_to_apply_rate_by_cnt_day14", "repay_to_apply_rate_by_cnt_day30",
|
||||||
|
"repay_to_apply_rate_by_cnt_day60", "repay_to_apply_rate_by_cnt_day90",
|
||||||
|
"repay_to_apply_rate_by_cnt_day180", "repay_to_apply_rate_by_cnt_day240",
|
||||||
|
"repay_to_apply_rate_by_cnt_day365", "repay_to_apply_rate_by_cnt_day730",
|
||||||
|
"repay_to_apply_rate_by_org_cnt_day3", "repay_to_apply_rate_by_org_cnt_day7",
|
||||||
|
"repay_to_apply_rate_by_org_cnt_day14", "repay_to_apply_rate_by_org_cnt_day30",
|
||||||
|
"repay_to_apply_rate_by_org_cnt_day60", "repay_to_apply_rate_by_org_cnt_day90",
|
||||||
|
"repay_to_apply_rate_by_org_cnt_day180", "repay_to_apply_rate_by_org_cnt_day240",
|
||||||
|
"repay_to_apply_rate_by_org_cnt_day365", "repay_to_apply_rate_by_org_cnt_day730"
|
||||||
|
),
|
||||||
|
"delinq_monitor", Set.of(
|
||||||
|
"overdue_to_apply_rate_by_org_cnt_day3", "overdue_to_apply_rate_by_org_cnt_day7",
|
||||||
|
"overdue_to_apply_rate_by_org_cnt_day14", "overdue_to_apply_rate_by_org_cnt_day30",
|
||||||
|
"overdue_to_apply_rate_by_org_cnt_day60", "overdue_to_apply_rate_by_org_cnt_day90",
|
||||||
|
"overdue_to_apply_rate_by_org_cnt_day180", "overdue_to_apply_rate_by_org_cnt_day240",
|
||||||
|
"overdue_to_apply_rate_by_org_cnt_day365", "overdue_to_apply_rate_by_org_cnt_day730",
|
||||||
|
"overdue_to_repay_rate_by_org_cnt_day3", "overdue_to_repay_rate_by_org_cnt_day7",
|
||||||
|
"overdue_to_repay_rate_by_org_cnt_day14", "overdue_to_repay_rate_by_org_cnt_day30",
|
||||||
|
"overdue_to_repay_rate_by_org_cnt_day60", "overdue_to_repay_rate_by_org_cnt_day90",
|
||||||
|
"overdue_to_repay_rate_by_org_cnt_day180", "overdue_to_repay_rate_by_org_cnt_day240",
|
||||||
|
"overdue_to_repay_rate_by_org_cnt_day365", "overdue_to_repay_rate_by_org_cnt_day730"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/** V2.2 overall_score 模块全量字段 */
|
||||||
|
private static final Map<String, Set<String>> SCORE_WHITELIST = Map.of(
|
||||||
|
"overall_score", Set.of(
|
||||||
|
"recent_risk_level_v1", "recent_risk_level_v2", "recent_risk_level_v3",
|
||||||
|
"recent_risk_level_v4", "recent_risk_level_v5",
|
||||||
|
"mid_risk_level_v1", "mid_risk_level_v2", "mid_risk_level_v3",
|
||||||
|
"mid_risk_level_v4", "mid_risk_level_v5",
|
||||||
|
"long_risk_level_v1", "long_risk_level_v2", "long_risk_level_v3",
|
||||||
|
"long_risk_level_v4", "long_risk_level_v5"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/** V2_FEATURE 白名单 = V1 + V2_ADDITIONS,懒加载 */
|
||||||
|
private static volatile Map<String, Set<String>> v2FeatureWhitelist;
|
||||||
|
|
||||||
|
private ResultFieldFilter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void filter(Map<String, Object> result, ResultFilterType type) {
|
||||||
|
if (result == null || result.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case V1_FEATURE:
|
||||||
|
filterByWhitelist(result, V1_WHITELIST);
|
||||||
|
break;
|
||||||
|
case V2_FEATURE:
|
||||||
|
filterByWhitelist(result, getV2FeatureWhitelist());
|
||||||
|
break;
|
||||||
|
case V2_SCORE:
|
||||||
|
filterByWhitelist(result, SCORE_WHITELIST);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void filterByWhitelist(Map<String, Object> result, Map<String, Set<String>> whitelist) {
|
||||||
|
result.entrySet().removeIf(entry -> !whitelist.containsKey(entry.getKey()));
|
||||||
|
for (Map.Entry<String, Object> entry : result.entrySet()) {
|
||||||
|
Set<String> allowedFields = whitelist.get(entry.getKey());
|
||||||
|
if (allowedFields != null && entry.getValue() instanceof Map) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> fields = (Map<String, Object>) entry.getValue();
|
||||||
|
fields.keySet().retainAll(allowedFields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Set<String>> getV2FeatureWhitelist() {
|
||||||
|
if (v2FeatureWhitelist == null) {
|
||||||
|
synchronized (ResultFieldFilter.class) {
|
||||||
|
if (v2FeatureWhitelist == null) {
|
||||||
|
Map<String, Set<String>> merged = new HashMap<>(V1_WHITELIST);
|
||||||
|
V2_ADDITIONS.forEach((module, additions) ->
|
||||||
|
merged.computeIfPresent(module, (k, existing) -> {
|
||||||
|
Set<String> combined = new java.util.LinkedHashSet<>(existing);
|
||||||
|
combined.addAll(additions);
|
||||||
|
return Set.copyOf(combined);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
v2FeatureWhitelist = Map.copyOf(merged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v2FeatureWhitelist;
|
||||||
|
}
|
||||||
|
}
|
||||||
199
对接接口文档.md
199
对接接口文档.md
|
|
@ -1,29 +1,40 @@
|
||||||
# 印尼支付行为画像查询接口
|
# 印尼支付行为画像查询接口
|
||||||
|
|
||||||
## 接口信息
|
## 接口概览
|
||||||
|
|
||||||
|
| 接口 | 路径 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| V1 特征 | `POST /api/v1/fortispay/payment-feature` | 返回 V1 版 536 个特征字段(6 模块) |
|
||||||
|
| V2 特征 | `POST /api/v1/fortispay/payment-feature-v2` | 返回 V2.2 版 606 个特征字段(6 模块,不含综合评分) |
|
||||||
|
| V2 评分 | `POST /api/v1/fortispay/payment-feature-v2-score` | 返回 V2.2 版 15 个综合评分字段(overall_score 模块) |
|
||||||
|
|
||||||
|
三个接口调用**同一三方 API**,入参、缓存、日志相同,仅响应 `data.result` 字段过滤规则不同。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 公共信息
|
||||||
|
|
||||||
| 项目 | 说明 |
|
| 项目 | 说明 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 接口路径 | `POST /api/v1/fortispay/payment-feature` |
|
|
||||||
| 请求格式 | `application/json; charset=UTF-8` |
|
| 请求格式 | `application/json; charset=UTF-8` |
|
||||||
| 响应格式 | `application/json` |
|
| 响应格式 | `application/json` |
|
||||||
|
|
||||||
## 请求头部
|
### 请求头部
|
||||||
|
|
||||||
| 参数 | 类型 | 必填 | 说明 |
|
| 参数 | 类型 | 必填 | 说明 |
|
||||||
|---|---|---|------------------------------|
|
|---|---|---|---|
|
||||||
| Content-Type | String | Y | `application/json` |
|
| Content-Type | String | Y | `application/json` |
|
||||||
| X-Request-Id | String | N | 网关请求唯一标识ID,用于全链路追踪,原样回显在响应头中 |
|
| X-Request-Id | String | N | 网关请求唯一标识ID,用于全链路追踪,原样回显在响应头中 |
|
||||||
| X-Language | String | N | 语言标识,传 `en` 返回英文结果,不传默认英文 |
|
| X-Language | String | N | 语言标识,传 `en` 返回英文结果,不传默认英文 |
|
||||||
|
|
||||||
## 响应头部
|
### 响应头部
|
||||||
|
|
||||||
| 参数 | 类型 | 说明 |
|
| 参数 | 类型 | 说明 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| X-Request-Id | String | 回显请求头中的 X-Request-Id,未传则自动生成 32 位 UUID |
|
| X-Request-Id | String | 回显请求头中的 X-Request-Id,未传则自动生成 32 位 UUID |
|
||||||
| X-Session-Id | String | 三方服务返回的唯一会话标识(Fortispay responseId) |
|
| X-Session-Id | String | 三方服务返回的唯一会话标识(Fortispay responseId) |
|
||||||
|
|
||||||
## 请求体
|
### 请求体
|
||||||
|
|
||||||
| 字段 | 类型 | 必填 | 说明 |
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|
|
@ -55,57 +66,9 @@
|
||||||
|
|
||||||
> id_card、mobile 传密文时必须传 encrypt_algo="MD5"。
|
> id_card、mobile 传密文时必须传 encrypt_algo="MD5"。
|
||||||
|
|
||||||
## 响应体
|
### 错误响应
|
||||||
|
|
||||||
服务透传三方接口原始响应,不做字段裁剪。
|
错误响应与三方接口响应保持相同结构,其中 `data` 中 `status=0`、`result=null`:
|
||||||
|
|
||||||
| 字段 | 类型 | 说明 |
|
|
||||||
|---|---|-------------------------------------------|
|
|
||||||
| code | String | 响应码,`"0"` 表示成功,更多请查看富通接口规范.pdf 常见响应编码表 |
|
|
||||||
| message | String | 提示消息,如 `"success"` |
|
|
||||||
| responseId | String | 三方响应的唯一标识ID |
|
|
||||||
| data | Object | 数据节点,包含 status 和 result |
|
|
||||||
| data.status | Integer | 查询状态,仅code为 `"0"` 时有值(`1` = 查得,`0` = 未查得) |
|
|
||||||
| data.result | Object | 结果数据(Map),三方返回的原始 result 对象 |
|
|
||||||
|
|
||||||
### 成功响应示例
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": "0",
|
|
||||||
"message": "success",
|
|
||||||
"responseId": "0b5a09b6ea7d77dbbbb92e05dc9744ad",
|
|
||||||
"data": {
|
|
||||||
"status": 1,
|
|
||||||
"result": {
|
|
||||||
"app_behavior": { "..." : "..." },
|
|
||||||
"loan_behavior": { "..." : "..." },
|
|
||||||
"repay_behavior": { "..." : "..." },
|
|
||||||
"time_structure": { "..." : "..." },
|
|
||||||
"delinq_monitor": { "..." : "..." },
|
|
||||||
"flow_anomaly": { "..." : "..." }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 未查得响应示例
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": "0",
|
|
||||||
"message": "success",
|
|
||||||
"responseId": "0b5a09b6ea7d77dbbbb92e05dc9744ad",
|
|
||||||
"data": {
|
|
||||||
"status": 0,
|
|
||||||
"result": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 错误响应
|
|
||||||
|
|
||||||
错误响应与三方接口响应保持相同结构,其中`data` 中 `status=0`、`result=null`:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -126,7 +89,26 @@
|
||||||
| 503 | 503 | 三方 API 网络不可达 |
|
| 503 | 503 | 三方 API 网络不可达 |
|
||||||
| 500 | 500 | 服务内部未知异常 |
|
| 500 | 500 | 服务内部未知异常 |
|
||||||
|
|
||||||
## 完整调用示例
|
---
|
||||||
|
|
||||||
|
## 一、V1 特征接口
|
||||||
|
|
||||||
|
`POST /api/v1/fortispay/payment-feature`
|
||||||
|
|
||||||
|
### 响应说明
|
||||||
|
|
||||||
|
`data.result` 只保留 V1.xlsx 中的 536 个字段,6 个模块:
|
||||||
|
|
||||||
|
| 模块 | 字段数 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `app_behavior` | 90 | 申请行为变量 |
|
||||||
|
| `loan_behavior` | 140 | 放款行为变量 |
|
||||||
|
| `repay_behavior` | 150 | 还款行为变量 |
|
||||||
|
| `time_structure` | 46 | 行为时间结构变量 |
|
||||||
|
| `delinq_monitor` | 50 | 逾期行为监控 |
|
||||||
|
| `flow_anomaly` | 60 | 资金流量异常监控变量 |
|
||||||
|
|
||||||
|
### 完整调用示例
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://{host}:{port}/api/v1/fortispay/payment-feature \
|
curl -X POST http://{host}:{port}/api/v1/fortispay/payment-feature \
|
||||||
|
|
@ -139,3 +121,106 @@ curl -X POST http://{host}:{port}/api/v1/fortispay/payment-feature \
|
||||||
"mobile": "6285887456612"
|
"mobile": "6285887456612"
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、V2 特征接口
|
||||||
|
|
||||||
|
`POST /api/v1/fortispay/payment-feature-v2`
|
||||||
|
|
||||||
|
### 响应说明
|
||||||
|
|
||||||
|
`data.result` 保留 V2.2.xlsx 中的 606 个特征字段(6 模块,不含综合评分):
|
||||||
|
|
||||||
|
| 模块 | 字段数 | 相比 V1 新增 |
|
||||||
|
|---|---|---|
|
||||||
|
| `app_behavior` | 90 | — |
|
||||||
|
| `loan_behavior` | 150 | +10(`credit_to_apply_rate_by_org_cnt_day*`) |
|
||||||
|
| `repay_behavior` | 190 | +40(还款与放款/申请的交叉比率) |
|
||||||
|
| `time_structure` | 46 | — |
|
||||||
|
| `delinq_monitor` | 70 | +20(逾期与申请/还款的交叉比率) |
|
||||||
|
| `flow_anomaly` | 60 | — |
|
||||||
|
|
||||||
|
> 注意:比率类字段类型为 `float`(V1 中为 `Int`)。
|
||||||
|
|
||||||
|
### 完整调用示例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://{host}:{port}/api/v1/fortispay/payment-feature-v2 \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "X-Request-Id: 9c6ccc0f3ad3886dfe56ed364b6dc3e8" \
|
||||||
|
-H "X-Language: en" \
|
||||||
|
-d '{
|
||||||
|
"name": "ABCXYZ",
|
||||||
|
"id_card": "3201190108990002",
|
||||||
|
"mobile": "6285887456612"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、V2 评分接口
|
||||||
|
|
||||||
|
`POST /api/v1/fortispay/payment-feature-v2-score`
|
||||||
|
|
||||||
|
### 响应说明
|
||||||
|
|
||||||
|
`data.result` 只保留 V2.2.xlsx 中 `overall_score` 模块的 15 个字段:
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `recent_risk_level_v1` ~ `v5` | Int | 申请人即时风险资质等级 V1~V5 |
|
||||||
|
| `mid_risk_level_v1` ~ `v5` | Int | 申请人阶段风险资质等级 V1~V5 |
|
||||||
|
| `long_risk_level_v1` ~ `v5` | Int | 申请人长效风险资质等级 V1~V5 |
|
||||||
|
|
||||||
|
### 成功响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": "0",
|
||||||
|
"message": "success",
|
||||||
|
"responseId": "0b5a09b6ea7d77dbbbb92e05dc9744ad",
|
||||||
|
"data": {
|
||||||
|
"status": 1,
|
||||||
|
"result": {
|
||||||
|
"overall_score": {
|
||||||
|
"recent_risk_level_v1": 7,
|
||||||
|
"recent_risk_level_v2": 70,
|
||||||
|
"recent_risk_level_v3": 8,
|
||||||
|
"recent_risk_level_v4": 18,
|
||||||
|
"recent_risk_level_v5": 35,
|
||||||
|
"mid_risk_level_v1": 46,
|
||||||
|
"mid_risk_level_v2": 47,
|
||||||
|
"mid_risk_level_v3": 30,
|
||||||
|
"mid_risk_level_v4": 87,
|
||||||
|
"mid_risk_level_v5": 51,
|
||||||
|
"long_risk_level_v1": 36,
|
||||||
|
"long_risk_level_v2": 37,
|
||||||
|
"long_risk_level_v3": 13,
|
||||||
|
"long_risk_level_v4": 16,
|
||||||
|
"long_risk_level_v5": 89
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 完整调用示例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://{host}:{port}/api/v1/fortispay/payment-feature-v2-score \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "X-Request-Id: 9c6ccc0f3ad3886dfe56ed364b6dc3e8" \
|
||||||
|
-H "X-Language: en" \
|
||||||
|
-d '{
|
||||||
|
"name": "ABCXYZ",
|
||||||
|
"id_card": "3201190108990002",
|
||||||
|
"mobile": "6285887456612"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 缓存说明
|
||||||
|
|
||||||
|
三个接口共享同一套缓存。缓存以原始三方响应存储,命中缓存后按接口版本过滤 `result` 字段返回。同一用户查询任意接口后,其他接口命中缓存均无需再次调用三方。
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue