> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clinkbill.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Portal 接口

> 使用 Portal token 读取账户数据、创建带短期激活链接的购买指令、绑定或删除支付方式、获取支付凭证，并回报商户支付结果。

这些接口都使用 [Portal token](https://docs.clinkbill.com/cn/api-reference/agent-portal/portal_token.md)，只访问 token 的 `sub` 对应用户。读取需要 `portal:read`；写入需要 `portal:write`，且只能操作用户自己的数据。

## 认证

```http theme={null}
Authorization: Bearer {PORTAL_TOKEN}
```

Gateway 校验 `aud=clink-agent-platform-portal`、`token_use=access` 和所需 scope，然后把验证后的客户身份传给 cwallet。请求中没有用于指定其他客户或邮箱的参数。

Clink 响应使用统一 envelope：

```json theme={null}
{
  "code": 200,
  "msg": "Success",
  "data": {}
}
```

以下示例展示 `data`。

## 通用行为

* `pageNum` 和 `pageSize` 使用从 1 开始的分页。
* 订单列表支持 `status`、`from`、`to` 过滤。
* 列表按用户隔离，不按 Agent 过滤；该用户下任意 Agent 创建的订单、退款和授权都会返回。
* 记录不存在，或记录属于其他用户时，返回 `404`。
* 写接口只限用户自己的风控规则、账单地址、购买指令、绑卡会话、支付凭证、支付结果和支付方式；其余接口只读。
* 写接口的请求金额使用主货币单位的十进制字符串：`"12.50"` 表示 USD 12.50。不要传最小单位。

## 获取账户信息

```http theme={null}
GET {API_BASE_URL}/agent/platform/me
```

```json theme={null}
{
  "customer_id": "ccus_...",
  "email": "user@example.com",
  "name": "Example User",
  "country": "US",
  "status": "READY"
}
```

| 字段 | 含义 |
| - | - |
| `customer_id` | Clink 客户 ID。 |
| `email` | 客户邮箱。 |
| `name` | 客户显示名。 |
| `country` | 账单地址国家，可能为空。 |
| `status` | 钱包就绪状态：`READY`、`NOT_READY` 或 `SUSPENDED`。`NOT_READY` 表示账户存在但没有可用的默认支付方式。 |

## 支付方式列表

```http theme={null}
GET {API_BASE_URL}/agent/platform/payment-methods
```

```json theme={null}
{
  "payment_methods": [
    {
      "payment_instrument_id": "pi_...",
      "payment_method_type": "CARD",
      "payment_instrument_type": "VIRTUAL_CARD",
      "card_scheme": "VISA",
      "card_last_four": "4242",
      "expiry_month": "12",
      "expiry_year": "2030",
      "issuer_bank": "Example Bank",
      "is_default": true,
      "status": "ACTIVE"
    }
  ]
}
```

`status` 为 `ACTIVE` 或 `DISABLED`。不会返回 PAN 或 CVV。`is_default` 标识默认卡；默认卡可以删除。

添加卡片请使用[绑定银行卡](#绑定银行卡)。如果要在一次流程中完成绑卡和购买授权，请在[创建指令](#创建指令)中省略 `payment_instrument_id`。删除卡片请使用[删除支付方式](#删除支付方式)。

## 绑定银行卡

为 token 对应用户创建短期绑卡会话，并返回一个供用户在浏览器中打开、完成绑卡的 URL。需要 `portal:write`。

该接口不创建指令，也不授权消费。用户只需要添加卡片时使用它；如果要一次完成绑卡和授权，请改用[创建指令](#创建指令)并省略 `payment_instrument_id`。

```http theme={null}
POST {API_BASE_URL}/agent/platform/bind-sessions
Authorization: Bearer {PORTAL_TOKEN}
```

请求中没有用于指定其他用户的 body 字段。会话始终为该 token 对应用户创建。

### 响应

```json theme={null}
{
  "session_id": "vs_...",
  "url": "https://agent.clinkbill.dev/vault/vs_...",
  "expires_at": "2026-11-09T10:30:00Z"
}
```

| 字段 | 含义 |
| - | - |
| `session_id` | 不透明的短期绑卡会话 ID。 |
| `url` | 供用户在浏览器中打开的短期绑卡链接。链接包含会话 ID，不含 portal token。 |
| `expires_at` | 链接失效时间。 |

每次调用都会创建一个新的独立会话，有效期较短。用户打开链接并完成绑卡流程后，卡片会加入该用户的支付方式（见[支付方式列表](#支付方式列表)）；不会创建指令或授权。会话处于 pending 状态时可以重新打开或重复兑换链接；绑卡流程完成或会话过期后链接失效。

> [!WARNING]
>
> 把绑卡链接当作凭证处理。不要转发、截图或写入日志；拿到链接的人可以在链接有效期内打开它，并为该用户完成绑卡。只把链接发给目标用户。

## 删除支付方式

删除 token 对应用户的一个支付方式。需要 `portal:write`。

```http theme={null}
DELETE {API_BASE_URL}/agent/platform/payment-methods/{paymentInstrumentId}
Authorization: Bearer {PORTAL_TOKEN}
```

```json theme={null}
{
  "deleted": true
}
```

| 字段 | 含义 |
| - | - |
| `deleted` | 删除成功时为 `true`。 |

删除成功返回 `200` 和 `deleted: true`。删除立即生效，响应不返回用户操作页面链接。支付方式不存在，或属于其他用户时，都返回相同的 `404`，因此响应不会泄露其他用户的卡是否存在。默认卡可以删除。删除成功后重复发起该请求会返回 `404`。

## 订单列表

```http theme={null}
GET {API_BASE_URL}/agent/platform/orders?pageNum=1&pageSize=20&status={STATUS}&from={ISO_DATE}&to={ISO_DATE}
```

| 参数 | 必填 | 含义 |
| - | - | - |
| `pageNum` | 否 | 页码，从 1 开始。 |
| `pageSize` | 否 | 每页数量。 |
| `status` | 否 | 订单状态过滤。 |
| `from` | 否 | 起始时间下界（包含）。 |
| `to` | 否 | 结束时间上界（包含）。 |

```json theme={null}
{
  "total": 2,
  "page_num": 1,
  "page_size": 20,
  "truncated": false,
  "records": [
    {
      "order_id": "order_...",
      "paid_time": "2026-01-01T00:00:00Z",
      "amount": 42.5,
      "currency": "USD",
      "display_amount": "$42.50",
      "status_code": 1,
      "status": "SUCCESS",
      "merchant_name": "Example Merchant",
      "payment_method_type": "CARD",
      "payment_method_label": "Visa •••• 4242",
      "payment_method_icon": "https://...",
      "payment_instrument_last_four": "4242",
      "agent_info": {
        "clientId": "agent_..."
      }
    }
  ]
}
```

`truncated: true` 表示带状态/时间过滤的扫描达到 Clink 内部扫描上限；`total` 描述已扫描记录，不一定是该用户完整匹配历史。不带过滤时只读取一页，不使用有界扫描。

## 订单详情

```http theme={null}
GET {API_BASE_URL}/agent/platform/orders/{orderId}
```

详情包含下单时间、金额拆分、商户、支付方式、卡组织、商品、收货地址和金额、`agent_info` 以及 `refund_summary`：

```json theme={null}
{
  "order_id": "order_...",
  "order_time": "2026-01-01T00:00:00Z",
  "amount": 42.5,
  "display_amount": "$42.50",
  "subtotal_amount": 40.0,
  "display_subtotal_amount": "$40.00",
  "currency": "USD",
  "status_code": 1,
  "status": "SUCCESS",
  "merchant_name": "Example Merchant",
  "merchant_url": "https://merchant.example",
  "payment_method_type": "CARD",
  "payment_method_label": "Visa •••• 4242",
  "payment_instrument_last_four": "4242",
  "card_scheme": "VISA",
  "credit_amount": 2.5,
  "display_credit_amount": "$2.50",
  "paid_amount": 42.5,
  "display_paid_amount": "$42.50",
  "products": [],
  "agent_info": {},
  "refund_summary": {
    "refund_count": 0,
    "refunded_amount": 0,
    "currency": "USD",
    "latest_status": null,
    "refunds": []
  }
}
```

## 退款列表

```http theme={null}
GET {API_BASE_URL}/agent/platform/refunds?pageNum=1&pageSize=20
```

```json theme={null}
{
  "total": 1,
  "page_num": 1,
  "page_size": 20,
  "records": [
    {
      "refund_order_id": "refund_...",
      "order_id": "order_...",
      "refund_amount": 10.0,
      "refund_currency": "USD",
      "status": "SUCCESS",
      "refund_reason": "Customer request",
      "payment_instrument_id": "pi_..."
    }
  ]
}
```

## 退款详情

```http theme={null}
GET {API_BASE_URL}/agent/platform/refunds/{refundOrderId}
```

返回单条退款，字段同上。退款属于其他用户时返回 `404`。

## 授权列表

```http theme={null}
GET {API_BASE_URL}/agent/platform/authorizations?pageNum=1&pageSize=20&status={STATUS}
```

| 参数 | 必填 | 含义 |
| - | - | - |
| `pageNum` | 否 | 页码，从 1 开始。 |
| `pageSize` | 否 | 每页数量。 |
| `status` | 否 | 授权状态过滤。 |

```json theme={null}
{
  "total": 1,
  "page_num": 1,
  "page_size": 20,
  "records": [
    {
      "instruction_id": "inst_...",
      "client_reference_id": "0f1e2d3c-...",
      "payment_instrument_id": "pi_...",
      "card_last_four": "4242",
      "card_type": "VIRTUAL_CARD",
      "card_scheme": "VISA",
      "title": "Example authorization",
      "description": "Purchase authorization",
      "total_amount_limit": 100.0,
      "currency_code": "USD",
      "effective_until_time": "2026-02-01T00:00:00Z",
      "is_recurring": false,
      "status": "ACTIVE",
      "agent_info": {},
      "mandates": [],
      "usages": []
    }
  ]
}
```

## 授权详情

```http theme={null}
GET {API_BASE_URL}/agent/platform/authorizations/{instructionId}
```

详情包含指令字段、`mandates` 和 `usages`。`usages` 是原始使用记录；Portal 展示已用和剩余金额时由调用方自行汇总。授权属于其他用户时返回 `404`。

授权响应中的 `client_reference_id` 是指令自身的字段。通过 portal 创建的指令由 Clink 生成随机值；它不是创建请求的 `request_id`，也不是取凭证和回报结果时发送的 `client_reference_id`。不要用它做对账。

## 创建指令

为 token 对应用户创建购买指令（消费授权），并返回短期激活链接；用户打开链接并在 Clink 签名页完成 Passkey 验证后，授权才会生效。需要 `portal:write`。

`payment_instrument_id` 决定使用哪种签约模式：

| 模式 | `payment_instrument_id` | 指令状态 | 激活链接 |
| - | - | - | - |
| 指定卡签约 | 传值 | `CREATED` | 打开该卡的授权页。 |
| 绑卡并签约 | 省略 | `PENDING` | 打开绑卡和授权流程，用户在一次 Passkey ceremony 中完成绑卡和授权。 |

指定卡签约时，从[支付方式列表](#支付方式列表)获取 `payment_instrument_id`。绑卡并签约时，不要发送卡号、CVV 或任何其他卡片字段；用户在 Clink 页面输入卡片信息。客户身份始终来自 token；请求体中没有 customer 或 email 字段。

激活链接的签名会话兑换完成后，指定卡指令继续进入 `/authorize/{paymentInstrumentId}?instructionId=...`；绑卡并签约指令继续进入 `/bind-authorize?instructionId=...`，用户在那里完成绑卡和授权（同一次 Passkey ceremony）。

```http theme={null}
POST {API_BASE_URL}/agent/platform/authorizations
Authorization: Bearer {PORTAL_TOKEN}
Content-Type: application/json
```

### 请求字段

| 字段 | 必填 | 含义 |
| - | - | - |
| `request_id` | 是 | 平台侧引用和幂等键，8–128 字符。 |
| `title` | 是 | 非空的指令标题。 |
| `description` | 否 | 指令说明。 |
| `payment_instrument_id` | 否 | 该用户已有的可用支付方式。省略时绑定新卡并签约。 |
| `is_recurring` | 否 | 是否为周期指令。为 `true` 时，每条 mandate 都必须有 `recurring_frequency`。 |
| `effective_until_time` | 否 | 指令最后可用时间，UTC 格式 `yyyy-MM-dd HH:mm:ss`。绑卡并签约模式下会被忽略：Clink 会用当前时间 + `pendingActivationWindowMinutes`（默认 7 天）覆盖该字段（以及每条 mandate 的 `effective_until_time`），请从指令读取实际值。 |
| `shipping_address` | 否 | 收货地址对象，包含 `name`、`line1`、`line2`、`line3`、`city`、`state`、`zip` 和 `country_code`。 |
| `mandates` | 是 | 一条或多条 mandate，结构见下表。 |

每条 mandate 包含：

| 字段 | 必填 | 含义 |
| - | - | - |
| `description` | 是 | 非空的授权消费用途。 |
| `amount_limit` | 是 | 主货币单位的正十进制字符串，最多 18 位整数、2 位小数。`"100.00"` 表示 USD 100.00。 |
| `currency_code` | 是 | 三字母币种代码。同一指令内的所有 mandate 必须使用同一币种。 |
| `recurring_frequency` | 周期指令必填 | `WEEKLY`、`MONTHLY` 或 `YEARLY`。`is_recurring` 为 `true` 时，每条 mandate 必填。 |
| `merchant_category_code` | 否 | 适用时填写商户品类限制。 |
| `preferred_merchant_name` | 否 | 偏好商户名称。 |
| `effective_until_time` | 否 | mandate 到期时间，UTC 格式 `yyyy-MM-dd HH:mm:ss`。绑卡并签约模式下会随指令有效期一起被覆盖；请从指令读取实际值。 |

### 请求示例

> [tab] 指定卡签约
>
> ```json theme={null}
> {
>   "request_id": "platform-ref-001",
>   "title": "Office supplies budget",
>   "description": "Monthly office supplies purchase",
>   "payment_instrument_id": "pi_...",
>   "is_recurring": false,
>   "effective_until_time": "2026-12-31 23:59:59",
>   "shipping_address": {
>     "name": "Example User",
>     "line1": "1 Market Street",
>     "line2": "Suite 100",
>     "line3": null,
>     "city": "San Francisco",
>     "state": "CA",
>     "zip": "94105",
>     "country_code": "US"
>   },
>   "mandates": [
>     {
>       "description": "Purchase office supplies",
>       "amount_limit": "100.00",
>       "currency_code": "USD",
>       "recurring_frequency": null,
>       "merchant_category_code": "5732",
>       "preferred_merchant_name": null,
>       "effective_until_time": null
>     }
>   ]
> }
> ```

> [tab] 绑卡并签约
>
> ```json theme={null}
> {
>   "request_id": "platform-ref-002",
>   "title": "Office supplies budget",
>   "description": "Monthly office supplies purchase",
>   "is_recurring": false,
>   "shipping_address": {
>     "name": "Example User",
>     "line1": "1 Market Street",
>     "line2": "Suite 100",
>     "line3": null,
>     "city": "San Francisco",
>     "state": "CA",
>     "zip": "94105",
>     "country_code": "US"
>   },
>   "mandates": [
>     {
>       "description": "Purchase office supplies",
>       "amount_limit": "100.00",
>       "currency_code": "USD",
>       "recurring_frequency": null,
>       "merchant_category_code": "5732",
>       "preferred_merchant_name": null,
>       "effective_until_time": null
>     }
>   ]
> }
> ```

### 响应

> [tab] 指定卡签约
>
> ```json theme={null}
> {
>   "instruction_id": "inst_...",
>   "status": "CREATED",
>   "payment_instrument_id": "pi_...",
>   "activation_url": "https://agent.clinkbill.dev/sign/ss_...",
>   "activation_expires_at": "2026-11-09T10:30:00Z"
> }
> ```

> [tab] 绑卡并签约
>
> ```json theme={null}
> {
>   "instruction_id": "inst_...",
>   "status": "PENDING",
>   "activation_url": "https://agent.clinkbill.dev/sign/ss_...",
>   "activation_expires_at": "2026-11-09T10:30:00Z"
> }
> ```

| 字段 | 含义 |
| - | - |
| `instruction_id` | 创建的指令 ID。 |
| `status` | 指令状态：指定卡签约时为 `CREATED`，绑卡并签约时为 `PENDING`。 |
| `payment_instrument_id` | 该指令使用的支付方式。绑卡并签约模式尚未绑卡，因此不返回或为 `null`。 |
| `activation_url` | 供用户确认指令的短期激活链接。绑卡并签约模式下，页面会在同一次 Passkey ceremony 中先收集卡片再授权。链接中只有不透明的签名会话 ID，不含 portal token；在有效期内可兑换为普通 Clink 浏览器登录态，支持重复兑换（例如用户刷新页面），并在到达 `activation_expires_at`（默认 30 分钟）或指令变为 `ACTIVE`／终态后失效。 |
| `activation_expires_at` | 激活链接失效时间。 |

> [!WARNING]
>
> 把激活链接当作凭证处理。不要转发、截图或写入日志；拿到链接的人可以在链接有效期内打开它，并取得该客户的 Clink 浏览器登录态。只把链接发给目标用户。

### 激活指令

创建指令不等于授权。指定已有卡的指令状态为 `CREATED`；需要绑卡的指令状态为 `PENDING`。两者都只有用户在 Clink 签名页完成 Passkey 验证后才变为 `ACTIVE`。链接在有效期内可以重新打开或刷新，但指令只能签署一次。

1. 让用户在浏览器中打开 `activation_url`。
2. `CREATED` 指令由用户确认卡片并完成 Passkey 验证；`PENDING` 指令由用户在同一次 ceremony 中完成绑卡和 Passkey 验证。页面会建立浏览器登录态并继续到授权步骤。
3. 轮询 `GET /agent/platform/authorizations/{instructionId}`，直到 `status` 为 `ACTIVE`。

如果用户没有完成该流程，指令保持 `CREATED` 或 `PENDING`，不会授权任何消费。链接只发给目标用户；它是激活链接，不是 portal token。

### 幂等

`request_id` 是幂等键，两种签约模式规则一致。Clink 默认保留幂等记录 24 小时；超过该窗口后，用同一 `request_id` 重试会新建一条指令。窗口内使用完全一致的参数重试会返回同一 `instruction_id`；对尚未签署的指令正常重试会返回新的激活链接。如果重试的 `request_id` 对应已签署或已终态的指令，Clink 返回该指令但不返回新的 `activation_url` 或 `activation_expires_at`（这两个字段会被省略）；请读取 `GET /agent/platform/authorizations/{instructionId}` 获取当前状态。相同 `request_id` 携带不同参数返回 `409`，`code` 为 `71211011`（`portal_conflict`）。

## 获取凭证

针对已激活的指令和 mandate，为一次购买获取一次性支付凭证。需要 `portal:write`。

响应有两种模式，取决于平台是否已在 Clink 登记公钥：

* **已登记公钥**（`matched: true`）：Clink 把卡字段密封到 `key`/`payload` 信封中，只有持有配对私钥的平台才能解密。
* **未登记公钥**（`matched: false`）：当服务端启用明文模式且 gateway 响应脱敏已生效时，Clink 在响应中以明文返回 DPAN 和动态 CVV。卡可以直接使用，但这些字段会以明文到达平台后端。

在 Clink 登记公钥即可使用加密模式；生产环境建议登记。

```http theme={null}
POST {API_BASE_URL}/agent/platform/credential
Authorization: Bearer {PORTAL_TOKEN}
Content-Type: application/json
```

### 登记平台公钥

联系 Clink 在目标环境登记平台的 RSA 公钥；公钥按平台 client name 映射。是否登记公钥决定响应模式：已登记时凭证密封到该公钥；未登记时，只有在服务端启用明文模式且 gateway 响应脱敏已生效的情况下才返回明文卡字段（MCP 等价的回退行为）；默认开关关闭时接口会 fail closed。生产使用前请先登记公钥。

> [!WARNING]
>
> 未登记公钥时，在服务端启用明文模式的前提下，响应会以明文把 DPAN 和动态 CVV 返回给平台后端。不要把这些字段写入日志、模型输入或普通存储，也不要在结账后保留。请在 Clink 登记公钥（生产环境建议）以切换到密封的 `key`/`payload` 模式。该明文回退行为与 MCP `get_credential` 一致。在 gateway 响应脱敏尚未生效的环境中不要启用明文模式：该模式由服务端 `portal-plaintext-enabled` 配置开关控制（默认关闭），开关关闭时接口会 fail closed 并返回 `71211012`（`credential_public_key_not_configured`），而不是明文卡字段。

### 请求字段

| 字段 | 必填 | 含义 |
| - | - | - |
| `instruction_id` | 是 | 该用户拥有的 `ACTIVE` 指令。 |
| `mandate_id` | 是 | 该指令下覆盖本次购买的 mandate。 |
| `client_reference_id` | 是 | 本次购买的平台侧引用和幂等键。请保存该值；回报结果时使用同一个值。 |
| `amount` | 是 | 交易金额，主货币单位十进制字符串。 |
| `currency_code` | 是 | 三字母币种代码。 |
| `merchant_url` | 是 | 商户结账页 URL，必须使用 HTTPS。 |
| `merchant_name` | 否 | 商户展示名。缺省时使用 `merchant_url` 的 host。 |
| `merchant_country_code` | 否 | 商户国家，ISO 3166-1 alpha-2。缺省为 `US`。 |
| `merchant_order_id` | 否 | 商户侧订单号（如可用）。 |
| `products` | 否 | 商品明细，字段见下表。 |
| `shipping_address` | 否 | 收货地址对象，字段与[创建指令](#创建指令)中的 `shipping_address` 相同。 |

`products` 中每个商品的字段：

| 字段 | 含义 |
| - | - |
| `product_id` | 商品标识。 |
| `product_name` | 商品名称。 |
| `quantity` | 数量。 |
| `unit_price` | 单价，主货币单位十进制字符串。 |
| `currency_code` | 三字母币种代码。 |
| `product_url` | 商品页 URL。 |

### 请求示例

```json theme={null}
{
  "instruction_id": "inst_...",
  "mandate_id": "mand_...",
  "client_reference_id": "platform-ref-001",
  "amount": "12.50",
  "currency_code": "USD",
  "merchant_url": "https://shop.example.com/checkout",
  "merchant_name": "Example Store",
  "merchant_country_code": "US",
  "merchant_order_id": "shop-order-1",
  "products": [
    {
      "product_id": "item-001",
      "product_name": "Example item",
      "quantity": 1,
      "unit_price": "12.50",
      "currency_code": "USD",
      "product_url": "https://shop.example.com/item-001"
    }
  ],
  "shipping_address": {
    "name": "Example User",
    "line1": "1 Market Street",
    "city": "San Francisco",
    "state": "CA",
    "zip": "94105",
    "country_code": "US"
  }
}
```

### 响应

`matched` 决定响应结构。

> [tab] 密文模式（matched: true）
>
> Clink 使用平台登记的公钥密封凭证，卡字段在 `payload` 内。
>
> ```json theme={null}
> {
>   "matched": true,
>   "key": "<RSA-OAEP wrapped AES key, Base64>",
>   "payload": "<AES-256-GCM ciphertext, Base64>",
>   "expires_at": "2026-11-09T10:10:00Z"
> }
> ```

> [tab] 明文模式（matched: false）
>
> 未登记公钥且服务端已启用明文模式，DPAN 和动态 CVV 以明文返回，可直接使用。
>
> ```json theme={null}
> {
>   "matched": false,
>   "expires_at": "<ISO-8601>",
>   "order_id": "order_...",
>   "payment_execution_detail_id": "ped_...",
>   "client_reference_id": "...",
>   "card": {
>     "number": "<DPAN>",
>     "securityCode": "<dynamic CVV>",
>     "expiryMonth": "12",
>     "expiryYear": "2028",
>     "expiry": "12/2028",
>     "dynamicDataType": "DAVV",
>     "dynamicDataExpiration": 1792380808,
>     "eci": "05",
>     "paymentAccountReference": "PAR-1"
>   },
>   "display": {
>     "brand": "VISA",
>     "last4": "3797"
>   }
> }
> ```

| 字段 | 含义 |
| - | - |
| `matched` | 已登记平台公钥、凭证以密封模式返回时为 `true`；未登记公钥且服务端已启用明文模式、卡字段以明文返回时为 `false`。 |
| `key` | 仅在 `matched` 为 `true` 时返回；`matched` 为 `false` 时省略。RSA-OAEP 包裹的 AES 密钥，Base64。 |
| `payload` | 仅在 `matched` 为 `true` 时返回；`matched` 为 `false` 时省略。凭证 payload 的 AES-256-GCM 密文，Base64。 |
| `order_id` | 仅在 `matched` 为 `false` 时返回；`matched` 为 `true` 时省略，ID 在解密后的 payload 内。本次凭证对应的订单。 |
| `payment_execution_detail_id` | 仅在 `matched` 为 `false` 时返回；`matched` 为 `true` 时省略，ID 在解密后的 payload 内。本次凭证对应的 payment execution detail。 |
| `client_reference_id` | 仅在 `matched` 为 `false` 时返回；`matched` 为 `true` 时省略，ID 在解密后的 payload 内。请求中发送的 `client_reference_id`；回报结果时需要。 |
| `card` | 仅在 `matched` 为 `false` 时返回；`matched` 为 `true` 时省略。明文卡字段（DPAN 和动态 CVV），见下表。 |
| `display` | 仅在 `matched` 为 `false` 时返回；`matched` 为 `true` 时省略。卡展示信息：`brand`（卡组织）和 `last4`（凭证卡号后四位）。 |
| `expires_at` | ISO-8601 时间戳，估计的有效期窗口，基于 Clink 默认凭证 TTL。权威有效期在 `card`（明文模式）或解密后的 payload（密文模式）中。 |

密封模式响应只包含 `matched`、`key`、`payload` 和 `expires_at`；此时 `card`、`display` 和 ID 字段会被省略，ID 在解密后的 payload 内。明文模式响应不包含 `key` 或 `payload`。

明文模式下 `card` 的字段：

明文模式下 `number` 和 `securityCode` 始终存在；其余字段可选，网络未提供时省略。

| 字段 | 含义 |
| - | - |
| `number` | 明文模式下必须返回。DPAN（凭证卡号），绝不是底层 PAN。 |
| `securityCode` | 明文模式下必须返回。凭证的动态安全码（CVV）。 |
| `expiryMonth` | 有效期月份，格式 `MM`。可选；所有有效期字段都可能缺失。 |
| `expiryYear` | 四位有效期年份。网络返回的两位年份会扩展为 `20YY`。可选。 |
| `expiry` | 网络返回的原始有效期字符串，格式为 `MM/YYYY` 或 `MM/YY`，不做归一化。可选。 |
| `dynamicDataType` | 动态数据在结账时的使用方式（例如 `DAVV`）。可选。 |
| `dynamicDataExpiration` | 动态数据有效期，Unix epoch 秒（数字类型）。可选；网络未提供时省略。 |
| `eci` | 电商指示符（ECI）。可选。 |
| `paymentAccountReference` | Payment Account Reference。可选。 |

### 解密密封响应

当 `matched` 为 `true` 时，使用平台私钥解密 `key` 和 `payload`。解密后的 payload 包含 `orderId`、`paymentExecutionDetailId`、`clientReferenceId`、`status`、网络凭证（DPAN、动态 CVV 和有效期）以及持卡人和地址字段。信封格式和解密示例见[解密](https://docs.clinkbill.com/cn/guides/agent/browser_pay/decryption.md)。

不要把解密后的卡字段写入日志、模型输入或普通记录，并以解密后 payload 中的有效期信息为准判断凭证可用时间；`expires_at` 只是估算。保存 `client_reference_id`；[回报支付结果](#回报支付结果)会用到它。

### 幂等

`client_reference_id` 是幂等键。使用相同 `client_reference_id` 重试会返回同一凭证：`matched` 为 `true` 时返回同一密封信封，明文模式下从服务端加密缓存返回同一张卡，不会重复签发。携带不同参数复用时返回 `409`，`code` 为 `71211011`（`portal_conflict`）。

## 回报支付结果

使用凭证后，回报在商户页面观察到的结果。需要 `portal:write`。Clink 用该回报闭环订单和指令 usage。回报只记录商户页面显示的结果，不会执行或验证支付。

> [!NOTE]
>
> 该接口是支付结果确认入口。它是确认或回报交易结果的唯一入口，Clink 不提供独立的“确认交易”接口。请在下方说明的 24 小时回报窗口内，通过该接口回报最终结果（包括在 `UNKNOWN` 回报之后补报最终结果）。

```http theme={null}
POST {API_BASE_URL}/agent/platform/credential-results
Authorization: Bearer {PORTAL_TOKEN}
Content-Type: application/json
```

### 请求字段

| 字段 | 必填 | 含义 |
| - | - | - |
| `client_reference_id` | 是 | 获取凭证时使用的值。Clink 按该值和 token 对应用户定位 usage。 |
| `outcome` | 是 | `SUCCEEDED`、`FAILED`、`NOT_SUBMITTED` 或 `UNKNOWN`，含义见下表。 |
| `paid_amount` | 否 | 商户页面显示的金额，主货币单位十进制字符串。必须与 `currency_code` 成对出现。 |
| `currency_code` | 否 | 三字母币种代码。必须与 `paid_amount` 成对出现。 |
| `failure_reason` | 否 | 失败或未提交原因。仅在 `FAILED` 或 `NOT_SUBMITTED` 时接受。 |

| Outcome | 含义 |
| - | - |
| `SUCCEEDED` | 商户明确确认支付成功。 |
| `FAILED` | 卡已提交后，商户明确显示失败。 |
| `NOT_SUBMITTED` | 卡从未提交。 |
| `UNKNOWN` | 卡已提交，但无法确定结果。Clink 不发布结果，返回 `PENDING` 和 `report_deadline`；请在该时间前回报最终结果。 |

`failure_reason` 接受 `CARD_DECLINED`、`AUTHENTICATION_REQUIRED`、`AMOUNT_CHANGED`、`CREDENTIAL_EXPIRED`、`CREDENTIAL_LOST`、`MERCHANT_ERROR`、`BUYER_CANCELLED` 或 `OTHER`。

### 请求示例

```json theme={null}
{
  "client_reference_id": "platform-ref-001",
  "outcome": "SUCCEEDED",
  "paid_amount": "12.50",
  "currency_code": "USD",
  "failure_reason": null
}
```

### 响应

```json theme={null}
{
  "status": "SUCCEEDED",
  "report_deadline": "2026-11-10T09:00:00Z",
  "paid_amount_mismatch": false
}
```

| 字段 | 含义 |
| - | - |
| `status` | 已记录的结果。`UNKNOWN` 回报返回 `PENDING`。 |
| `report_deadline` | 可回报最终结果的最晚时间。 |
| `paid_amount_mismatch` | `paid_amount` 与授权金额不一致时为 `true`。该回报不会覆盖授权金额。 |

### 回报规则

* Clink 在 `report_deadline` 之前接受最终结果，即凭证签发后 24 小时。超过窗口的回报返回 `410`，`code` 为 `71211018`（`report_window_expired`）。
* usage 不存在或不属于 token 对应用户时返回 `404`。
* Clink 按两类比较最终结果：`SUCCEEDED` 属于成功类；`FAILED` 和 `NOT_SUBMITTED` 都属于失败类。同一类内重复回报会以 HTTP `200` 返回已记录的结果；例如已记录 `NOT_SUBMITTED` 后再回报 `FAILED` 不冲突。已记录终态后回报另一类结果返回 `409`，`code` 为 `71211017`（`result_already_reported`）。
* `SUCCEEDED`、`FAILED` 和 `NOT_SUBMITTED` 会闭环 usage，并进入 Clink 既有的支付结果处理链路。
* `UNKNOWN` 不记录终态、不发布结果消息，返回 `PENDING`；请在 `report_deadline` 之前回报最终结果。
* `paid_amount` 和 `currency_code` 必须成对出现。`paid_amount` 与授权金额不一致时，Clink 记录 `paid_amount_mismatch: true`，不覆盖授权金额。

## 风控规则

读取或全量替换用户的全局默认风控规则。

```http theme={null}
GET {API_BASE_URL}/agent/platform/risk-rules
PUT {API_BASE_URL}/agent/platform/risk-rules
Authorization: Bearer {PORTAL_TOKEN}
Content-Type: application/json
```

| 字段 | 类型 | PUT 必填 | 含义 |
| - | - | - | - |
| `singleRechargeLimit` | number | 是 | 单次充值上限（USD），最小 1。 |
| `dailyTotalLimit` | number | 是 | 每日充值总上限（USD），最小 1。 |
| `dailyMaxCount` | integer | 是 | 每日最多充值次数，最小 1。 |
| `rechargeInterval` | string | 是 | 冷却间隔，如 `5m`、`10m`、`30m`、`1h`。 |
| `manualApprovalThreshold` | number | 否 | 大额手动审批阈值（USD）。 |
| `manualApprovalEnabled` | boolean | 是 | 是否启用大额手动审批。 |
| `updatedAt` | string | 仅响应 | 最后更新时间。 |

```json theme={null}
{
  "singleRechargeLimit": 500,
  "dailyTotalLimit": 2000,
  "dailyMaxCount": 5,
  "rechargeInterval": "30m",
  "manualApprovalThreshold": 1000,
  "manualApprovalEnabled": true,
  "autoSuspendEnabled": true
}
```

`autoSuspendEnabled` 在当前版本是固定安全行为：Clink 始终返回 `true`，写入值会被忽略。请求 schema 为兼容保留该字段，但不能用它关闭自动暂停。PUT 返回保存后的规则。只有 `portal:read` 的 token 可以读，但 PUT 返回 `403`。

## 账单地址

读取或替换用户的账单地址。

```http theme={null}
GET {API_BASE_URL}/agent/platform/billing-address
PUT {API_BASE_URL}/agent/platform/billing-address
Authorization: Bearer {PORTAL_TOKEN}
Content-Type: application/json
```

| 字段 | 类型 | PUT 必填 | 含义 |
| - | - | - | - |
| `country` | string | 是 | 国家/地区。 |
| `region` | string | 是 | 州/省/地区。 |
| `city` | string | 是 | 城市。 |
| `line1` | string | 是 | 街道地址。 |
| `line2` | string | 否 | 地址第二行。 |
| `postal_code` | string | 是 | 邮编。 |
| `status` | string | 仅响应 | 地址状态；写入时忽略。 |

```json theme={null}
{
  "country": "US",
  "region": "CA",
  "city": "San Francisco",
  "line1": "1 Market Street",
  "line2": "Suite 100",
  "postal_code": "94105"
}
```

PUT 返回更新后的地址。Clink 校验必填字段，并复用现有 wallet 账单地址规则（配置国家名单，以及这些国家的 city/line1 要求）。只有 `portal:read` 的 token PUT 返回 `403`。

## 错误

业务错误使用同一个 envelope，不带 `data`：`code` 是数字业务码，`msg` 是人类可读描述。判断错误时以 HTTP 状态和 `code` 为准，不要依赖字符串错误码。

| HTTP status | 含义 |
| - | - |
| `400` | 查询参数、请求体或账单地址无效。 |
| `401` | Portal token 缺失、过期或无效。 |
| `403` | token audience/scope 不正确、缺少 scope，或误用了平台 client token。 |
| `404` | 记录不存在，或不属于 token 对应用户。 |
| `409` | 冲突：幂等 `request_id` 或 `client_reference_id` 携带不同参数（`portal_conflict`，`code` `71211011`），或已记录终态后回报了另一类最终结果（`result_already_reported`，`code` `71211017`）。 |
| `410` | 凭证结果回报窗口已过期（`report_window_expired`，`code` `71211018`）。 |
| `429` | 超过限流。 |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.