# 归因结果回传

#### 功能介绍

应用归因服务将满足隐私要求的归因结果回传给开发者、获胜的分发平台以及分发平台配置的归因监测平台。

#### 接口原型

*   **承载协议：** HTTPS POST
    
*   **接口方向：** 华为应用归因端侧 -> （分发平台/开发者/归因监测平台）
    
*   **接口URL：** 应用生态伙伴在归因云端管理台注册归因角色时填写的URL地址
    
*   **数据格式：**
    
    请求消息： Content-Type: application/json
    
    响应消息： Content-Type: application/json
    

#### 请求参数

**Request Body**

| 参数 | 参数类型 | 是否必选 | 是否参与签名 | 描述 |
| --- | --- | --- | --- | --- |
| ad_tech_id | String | 否 | 是 | 归因成功的分发平台id，分发平台向应用归因云侧注册角色时，由应用归因服务分配，长度固定为8个字符如果接收方为分发平台，该id即分发平台自身的id。 如果接收方为归因监测平台/开发者，该id为归因监测平台/开发者注册转化时指定分发平台列表中归因成功的分发平台id。 |
| campaign_id | String | 否 | 是 | 本次转化归因到的营销任务id，仅当满足回传条件时携带。 |
| source_id | String | 否 | 是 | 媒体应用id，长度不超过64个字符，仅当满足回传条件时携带。 |
| destination_id | String | 否 | 是 | 开发者应用id，长度不超过64个字符 。 说明： 您的应用ID参考查看应用基本信息获取。 |
| service_tag | String | 否 | 否 | 业务标识。 回传分发平台时，为分发平台关注的业务信息，如创意、素材等； 回传开发者时，为开发者关注的业务信息，如激活、付费相关营销链接信息。 说明： 通过申请开通权限方式向分发平台、开发者开放。 |
| business_scene | number | 否 | 否 | 业务场景值，仅开发者满足回传条件时携带。 取值范围：[0,99]。 说明： 通过申请开通权限方式向开发者开放。 |
| trigger_data | number | 否 | 是 | 转化事件编码。 标准转化事件取值范围：[1, 200]。 自定义转化事件取值范围：[501, 600]。 |
| installation_status | number | 否 | 否 | 应用安装状态。 说明： 通过申请开通权限方式向应用生态伙伴（分发平台、开发者、归因监测平台）开放。 |
| nonce | String | 是 | 是 | 用于计算签名的随机数，不带"-"，由应用归因服务生成，每次归因结果回传，nonce唯一。 |
| timestamp | number | 是 | 是 | 回传发生的时间戳，建议校验时判断与当前时间相差不超过5min，unix时间戳，毫秒。 |
| signature | String | 是 | 否 | 签名值。接收方应使用应用归因服务提供的公钥，对该签名值进行验签，具体参考验签计算规则、回传结果验签方法。 |
| adSourceTime | String | 是 | 否 | 回传获胜方来源登记营销事件发生时间。 说明： 通过申请开通权限方式向应用生态伙伴（分发平台、开发者、归因监测平台）开放。 |
| transaction_id | String | 是 | 否 | 本次回传的事务id，唯一，接收方可用于请求的幂等处理。 |

#### 请求示例

```
POST 
Content-Type: application/json
{
    "ad_tech_id":"12345678",
    "campaign_id":"50",
    "source_id":"108****321",
    "destination_id":"101****678",
    "trigger_data":12,
    "nonce":"17aa292c****4516****25150****195",
    "timestamp":167****380,
    "signature":"MEQCIEQlmZ****zKBSE8QnhLTIHZZZ****ZpRqRxHss65Ko****JgJKjdrWdkL****juEx2RmFS7da****ZRVZ8RyMyUXg==",
    "transaction_id":"aa****aaaa"
}
```

#### 响应参数

**Response Header**

| 参数 | 参数类型 | 是否必选 | 描述 |
| --- | --- | --- | --- |
| Content-Type | String | 是 | 取值为：application/json; charset=UTF-8 |

**Response Body**

| 参数 | 参数类型 | 是否必选 | 描述 |
| --- | --- | --- | --- |
| resultCode | String | 是 | 应用归因侧解析application/json类型响应，“0”表示成功，其他值失败。 |
| resultDesc | String | 是 | 结果描述。 |

#### 响应示例

```
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
{
  "resultCode": "0",
  "resultDesc": "Success."
}
```

#### 回传结果验签方法

1.  您需要在pom.xml文件中引入最新版本的开源密码算法包Bouncy Castle。
    
    ```
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcprov-jdk18on</artifactId>
      <version>${last_version}</version>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>${last_version}</version>
    </dependency>
    ```
    
2.  您可以使用以下代码对回传请求中签名值进行验签。
    
    ```
    import org.apache.commons.codec.binary.Base64;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import java.nio.charset.StandardCharsets;
    import java.security.InvalidKeyException;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.PublicKey;
    import java.security.Security;
    import java.security.Signature;
    import java.security.SignatureException;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.X509EncodedKeySpec;
    
    /**
     * 回传结果验签工具类
     *
     * @author ******
     * @since ****-**-**
     */
    public class PostbackResultVerifyUtil {
        private static String publicKey = "MIIBoj*****AAE=";
        private static final String RSA_ALGORITHM = "RSA";
        private static final String SHA256WithRSA_PSS_ALGORITHM = "SHA256WithRSA/PSS";
    
        /**
         * 回传结果验签调用方法
         *
         * @param content 签名内容拼接字段
         * @param signature 回传请求中的签名值
         * @return 验签结果
         * @throws NoSuchAlgorithmException NoSuchAlgorithmException
         * @throws InvalidKeySpecException InvalidKeySpecException
         * @throws InvalidKeyException InvalidKeyException
         * @throws SignatureException SignatureException
         */
        public boolean verify(String content,String signature)
            throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
            byte[] plainContent = content.getBytes(StandardCharsets.UTF_8);
            byte[] signContent = decodeBase64(signature);
            Security.addProvider(new BouncyCastleProvider());
            PublicKey pubKey = getPublicKey(publicKey);
            Signature rsaSignature = Signature.getInstance(SHA256WithRSA_PSS_ALGORITHM);
            rsaSignature.initVerify(pubKey);
            rsaSignature.update(plainContent);
            return rsaSignature.verify(signContent);
        }
    
        private PublicKey getPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodeBase64(key));
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            return keyFactory.generatePublic(keySpec);
        }
    
        private byte[] decodeBase64(String base64Str) {
            return Base64.decodeBase64(base64Str.getBytes(StandardCharsets.UTF_8));
        }
    }
    ```
    
    回传结果验签调用方法verify(String content,String signature)中：
    
    content：签名内容拼接字段，拼接方式可参考验签计算规则。
    
    signature：回传请求中的签名值。