# Webhook 回调

Webhook 让您可以异步收到通知：AI 任务跑完，状态是 `success` 还是 `error`，都会推送给您指定的 HTTP 端点。通知遵循 [Standard Webhooks 规范](https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md)。

#### Webhook 密钥

##### Webhook 密钥是怎么构成的

我们采用 **HMAC-SHA256** 签名方案的 webhook 密钥。密钥经 base64 编码，并加上 `whsec_` 前缀，方便一眼认出。

webhook 密钥示例：

`whsec_NDQzMzYxNzkzMzE0NjYyNDM6OTIxOTcwNDIxODQ`

##### 用 Standard Webhooks 官方库实现 Webhook

我们强烈建议使用 **Standard Webhooks Library** 的官方实现，签名校验的细节就不用您操心了。

用官方实现还能保证签名校验既安全又正确。

**[https://github.com/standard-webhooks/standard-webhooks/tree/main?tab=readme-ov-file#reference-implementations](https://github.com/standard-webhooks/standard-webhooks/tree/main?tab=readme-ov-file#reference-implementations)**

##### 自己实现 Webhook

请先弄懂 webhook 密钥的构成，参见[签名方案](https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md#signature-scheme)中的对称密钥部分。

给签名输入内容做签名时，请去掉 `whsec_` 前缀，再把剩下的字符串做 base64 解码，得到密钥的真实字节，用它来做 **HMAC-SHA256** 哈希。

#### Webhook 请求示例

```http
POST https://yourdomain.com/webhook-endpoint
Content-Type: application/json
webhook-id: msg_1eWPv9cWJCnEP99UJncmVJ6KjK_xVXRhZPe_eSGnRNbLlXEPjiG3gb3Usg9le3_4:1761112848
webhook-timestamp: 1761112900
webhook-signature: v1,vyVNWrjoZcBK1JXrFGkdDKK2slo5+Q5yfzpkHmqO5R0=
```

```json
{
  "created_at": 1761112848,
  "data": {
    "task_id": "1eWPv9cWJCnEP99UJncmVJ6KjK_xVXRhZPe_eSGnRNbLlXEPjiG3gb3Usg9le3_4",
    "task_status": "success"
  }
}
```

#### HTTP 请求头

##### `webhook-id`

这次 webhook 投递的唯一标识。
重试时这个值保持不变，可以拿来做幂等处理。

##### `webhook-timestamp`

webhook 发出时的 Unix 时间戳（秒）。

##### `webhook-signature`

'v1'，一个逗号（,），再跟上 base64 编码后的 **HMAC-SHA256** 签名。

'v1' 表示签名方案的版本，目前只支持这一个版本。

base64 编码后的 **HMAC-SHA256** 签名，是用您的 webhook 密钥对签名输入内容签名后的结果。

签名输入的格式：

```
{webhook-id}.{webhook-timestamp}.{raw-minified-json-body}
```

**签名内容示例：**

```
msg_1eWPv9cWJCnEP99UJncmVJ6KjK_xVXRhZPe_eSGnRNbLlXEPjiG3gb3Usg9le3_4:1761112848.1761112900.{"created_at":1761112848,"data":{"task_id":"1eWPv9cWJCnEP99UJncmVJ6KjK_xVXRhZPe_eSGnRNbLlXEPjiG3gb3Usg9le3_4","task_status":"success"}}
```

#### 请求体

##### `created_at`

Unix 时间戳（秒），表示任务完成的时间。

##### `data`

事件的具体内容。

| 字段 | 说明 |
|  --- | --- |
| `task_id` | 创建任务时返回的任务标识。用它查询任务的最终结果。 |
| `task_status` | 任务完成状态。取值有：`success`、`error`。 |


## 集成指南

### Webhook 集成指南

1. **在您的服务器上准备好一个 webhook 接收端点。**
该端点要能接受 `POST` 请求，并且可以通过 HTTPS 访问。
2. **在 API 控制台里创建一个 webhook。**
3. **跑一个 AI 任务，记下 `task_id`。**
4. **处理 webhook 通知，用 `task_id` 取回任务结果。**


#### 创建 Webhook 接收端点

进入 API 控制台的 Webhook 管理页：

**[https://yce.makeupar.com/api-console/en/webhook/](https://yce.makeupar.com/api-console/en/webhook/)**

##### 1. 找到 Webhook 区块

![](https://bcw-media.s3.ap-northeast-1.amazonaws.com/strapi/assets/webhook_main_bae171663b.png)

##### 2. 新建一个 Webhook 接收端点

![](https://bcw-media.s3.ap-northeast-1.amazonaws.com/strapi/assets/webhook_create_cd28e68fa3.png)

最多可以同时配置 **10 个 webhook 接收端点**。

##### 3. 保管好您的 Webhook 密钥

webhook 密钥用来校验 `webhook-signature`。
请务必妥善保存，切勿公开外泄。

![](https://bcw-media.s3.ap-northeast-1.amazonaws.com/strapi/assets/webhook_secret_key_6fe757a7de.png)

##### 4. 管理已有的 Webhook

![](https://bcw-media.s3.ap-northeast-1.amazonaws.com/strapi/assets/webhook_manage_endpoints_3bed715de9.png)

## 验证签名

#### 在服务器上处理 Webhook 请求

我们建议使用 **Standard Webhooks Library** 的官方实现：

**[https://github.com/standard-webhooks/standard-webhooks/tree/main?tab=readme-ov-file#reference-implementations](https://github.com/standard-webhooks/standard-webhooks/tree/main?tab=readme-ov-file#reference-implementations)**

这样能保证签名校验既安全又正确。

您也可以用 **Standard Webhooks Simulator** 来测试或调试推送内容：

**[https://www.standardwebhooks.com/simulate](https://www.standardwebhooks.com/simulate)**

#### 校验 Webhook 签名

来看这个 webhook 请求示例：

```http
POST https://yourdomain.com/webhook-endpoint
Content-Type: application/json
webhook-id: msg_1eWPv9cWJCnEP99UJncmVJ6KjK_xVXRhZPe_eSGnRNbLlXEPjiG3gb3Usg9le3_4:1761112848
webhook-timestamp: 1761112900
webhook-signature: v1,vyVNWrjoZcBK1JXrFGkdDKK2slo5+Q5yfzpkHmqO5R0=
```

请求体：

```json
{
  "created_at": 1761112848,
  "data": {
    "task_id": "1eWPv9cWJCnEP99UJncmVJ6KjK_xVXRhZPe_eSGnRNbLlXEPjiG3gb3Usg9le3_4",
    "task_status": "success"
  }
}
```

签名输入格式如下：

```
{webhook-id}.{webhook-timestamp}.{raw-minified-json-body}
```

签名内容示例：

```
msg_1eWPv9cWJCnEP99UJncmVJ6KjK_xVXRhZPe_eSGnRNbLlXEPjiG3gb3Usg9le3_4:1761112848.1761112900.{"created_at":1761112848,"data":{"task_id":"1eWPv9cWJCnEP99UJncmVJ6KjK_xVXRhZPe_eSGnRNbLlXEPjiG3gb3Usg9le3_4","task_status":"success"}}
```

用您的 webhook 密钥，对签名内容做 HMAC-SHA256 运算，再与收到的 webhook-signature 比对。
示例：

```
v1,vyVNWrjoZcBK1JXrFGkdDKK2slo5+Q5yfzpkHmqO5R0=
```