# 保存服务授权凭证

`POST` `/api/agent/finx/saveAuthCredential`

提交当前身份在指定服务/工具上的授权凭证。

**调用流程**：先调 getAuthSchema 拿到 authType 与 fields[]，确定本次要提交哪些 key；再调本接口提交 credentials。

**增量更新**：未传入的字段保留上次的值，要清空请显式传空字符串。

**完成后自动校验**：所有必填字段补齐后，系统会立即对凭证发起一次连通性校验（HTTP 服务发 HEAD 请求，MCP 服务执行 listTools），结果在响应的 verified / verifyMessage 中返回。

**key 命名规则与各鉴权类型的提交样例**见 credentials 参数说明。

身份说明：当您通过API访问本系统时，请求头中必须传递 X-Principal-Id 以标识操作主体；当您通过页面访问本系统时，无需传递。

## 请求参数

### 请求头参数

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| X-Principal-Id | integer | 否 | 身份主体ID（Long类型）。通过API访问时必须传递以标识操作主体；通过页面访问时无需传递。可通过「身份主体」模块的创建接口获取。 |

### 请求体（JSON）

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| agentId | integer | 是 | 智能体ID，凭证在该智能体下生效 |
| serviceName | string | 是 | 服务标识名，与 getAuthSchema 使用同一个值 |
| toolName | string | 否 | 工具标识名。不传（null）表示为整个服务配置凭证（服务级授权，最常用）；仅当该服务下某个工具使用独立凭证时才需要传工具名 |
| credentials | object | 是 | **凭证键值对（key 与 getAuthSchema 返回的 fields[].key 一一对应）**

**调用流程**
- 先调用 getAuthSchema 获取该服务/工具的 authType 与 fields[]，确定本次需要提交哪些 key
- 再调用本接口提交 credentials：**增量更新**，未传入的字段保留上次的值，要清空请显式传空字符串
- 所有必填字段补齐后，系统会立即对凭证发起一次连通性校验（HTTP 服务发 HEAD 请求，MCP 服务执行 listTools），结果在响应的 verified / verifyMessage 中返回

**key 命名规则**
- `credential`：API_KEY / BEARER / BASIC 的主凭证字段
- `customHeaders.<请求头名>`：CUSTOM 类型的某个自定义请求头
- `queryParams.<参数名>`：URL 查询参数，任意 authType 都可叠加
- 不在 getAuthSchema 的 fields[].key 列表内的 key 会被拒绝并报错

**各 authType 的 credentials 写法示例**
- API_KEY（值为 API 密钥明文，运行时按 `<headerName>: <值>` 注入请求头，headerName 默认 `X-API-Key`）：`{"credential":"sk-abcdef123456"}`
- BEARER（值为令牌本身，**不要带 `Bearer ` 前缀**，运行时自动注入 `Authorization: Bearer <值>`）：`{"credential":"eyJhbGciOiJIUzI1NiJ9.payload.sig"}`
- BASIC（值为 `base64(用户名:密码)`，运行时自动注入 `Authorization: Basic <值>`）：`{"credential":"dXNlcjpwYXNz"}`
- CUSTOM（服务模板声明的每个自定义请求头都要填）：`{"customHeaders.X-App-Id":"123","customHeaders.X-App-Secret":"abc"}`
- CUSTOM_HTTP_TOKEN（令牌由服务的 tokenFetchConfig 在运行时自动换取，通常无需提交 credential；若模板要求填写换取令牌所需的密钥，按 getAuthSchema 返回的字段提交）：`{"customHeaders.X-Client-Secret":"abc"}`
- NONE（一般无需调用本接口，仅当服务在 queryParams 上要求用户提供值时才需要）：`{"queryParams.api_key":"xxx","queryParams.app_id":"123"}`
- 叠加 URL 参数（可与上述任意类型组合）：`{"credential":"my-token","queryParams.app_id":"123"}`

**凭证安全**：提交的凭证加密存储，任何查询接口都只回显含 `***` 的脱敏值 |

## 响应

### 200

| 参数名 | 类型 | 说明 |
|--------|------|------|
| httpStatusCode | integer | HTTP状态码 |
| message | string | 响应消息 |
| data | FinxSaveAuthCredentialResult | 响应数据 |
|     updated | boolean | - |
|     complete | boolean | - |
|     remainingMissingFields | array | - |
|     verified | boolean | - |
|     verifyMessage | string | - |
| success | boolean | 是否成功 |
| requestId | string | 上游请求ID，用于跨系统链路追踪排查问题 |
| errCode | string | 上游错误码，前端可据此做特殊UI处理 |

### 400

| 参数名 | 类型 | 说明 |
|--------|------|------|
| httpStatusCode | integer | HTTP状态码 |
| message | string | 响应消息 |
| data | object | 响应数据 |
| success | boolean | 是否成功 |
| requestId | string | 上游请求ID，用于跨系统链路追踪排查问题 |
| errCode | string | 上游错误码，前端可据此做特殊UI处理 |

### 500

| 参数名 | 类型 | 说明 |
|--------|------|------|
| httpStatusCode | integer | HTTP状态码 |
| message | string | 响应消息 |
| data | object | 响应数据 |
| success | boolean | 是否成功 |
| requestId | string | 上游请求ID，用于跨系统链路追踪排查问题 |
| errCode | string | 上游错误码，前端可据此做特殊UI处理 |

