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

# 管理外部引用 ID

**外部引用 ID** 是您为某个 Fluz 用户自定义的标识符。它使您能够使用系统中已有的 ID 操作 Fluz API——而无需为每位用户存储或传递 Fluz 的内部 `userId` 和 `accountId`。

当用户授权您的应用时，您会将自己的标识符附加到该授权上。Fluz 会存储您的标识符与该用户的 Fluz 账户之间的配对关系，作用域限定在您的应用内。从那一刻起，您就可以在生成令牌、发送转账以及匹配 webhook 事件时使用您自己的 ID 来引用该用户。

> 📘 **您会在哪里看到它**
>
> 该字段在 OAuth 授权 URL 中显示为 `external_id`，在 GraphQL API 和 webhook 载荷中显示为 `externalReferenceId`。它们的值相同。

## 它可以是什么？

| 属性  | 规则                                                                       |
| --- | ------------------------------------------------------------------------ |
| 类型  | 任意字符串。Fluz 不强制规定格式。                                                      |
| 唯一性 | 在**您的应用内**必须对每位用户唯一。一个外部引用 ID 精确映射到一个 Fluz 用户。                           |
| 作用域 | 作用域为您的 OAuth 客户端。同一个 Fluz 用户在其他开发者的应用中可以携带不同的外部引用 ID，且其他应用不可见也不可使用您的 ID。 |
| 稳定性 | 将其视为不可变。请使用系统中的稳定标识符——如内部用户 ID 或 UUID。                                   |

> ⚠️ **不要使用 PII 作为外部引用 ID**
>
> 避免使用电子邮件地址、电话号码或姓名。这些信息可能会随时间变更并破坏映射关系，而且会不必要地在 URL 和令牌中传输个人数据。UUID 或数据库主键是正确选择。

## 我们在哪些场景使用它？

外部引用 ID 会流经四个界面：

| 场景                           | 字段                                | 方向       |
| ---------------------------- | --------------------------------- | -------- |
| OAuth 授权 URL                 | `external_id` 查询参数                | 您 → Fluz |
| `generateUserAccessToken` 变更 | `externalReferenceId` 参数          | 您 → Fluz |
| 钱包转账（`createTransfer`）       | `destination.externalReferenceId` | 您 → Fluz |
| Webhook 事件载荷                 | `externalReferenceId`             | Fluz → 您 |

它也会被嵌入到为用户签发的 OAuth 访问令牌中，因此该关联会在刷新令牌时持续存在。

## 我们如何使用它？

### 1. 在 OAuth 授权流程中指定它

当您将终端用户引导至授权 URL（参见 [Client facing OAuth grant flow](/client-facing-o-auth-grant-flow)）时，附加您的标识符作为 `external_id` 查询参数：

```text theme={null}
https://uni.staging.fluzapp.com/authorize?response_type=code&client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&scopes=MAKE_DEPOSIT%20LIST_PAYMENT&external_id=usr_8f3d2a91
```

当用户完成授权后，Fluz 会将 `usr_8f3d2a91` 记录在该用户对您应用的授权上。嵌入式小部件启动时也适用同一参数——参见 [Widget Overview](/developers/widgets)。

> 🚧 **小部件应用的必填项**
>
> 所有小部件应用类型（充值、付款、收款、virtual card、gift card 目录、账单支付以及外部付款小部件）在建立用户会话时**必须**提供外部引用 ID。若缺失，请求将被以 `External reference ID is required for <type> applications` 拒绝。对于标准 OAuth 应用，此项可选，但强烈建议使用。

### 2. 使用它生成用户访问令牌

一旦配对存在，`generateUserAccessToken` 可接受 `externalReferenceId` 来替代 `userId` 和 `accountId`：

```graphql theme={null}
mutation {
  generateUserAccessToken(
    externalReferenceId: "usr_8f3d2a91"
    scopes: [MAKE_DEPOSIT, LIST_PAYMENT]
  ) {
    token
    refreshToken
    scopes
  }
}
```

像往常一样使用您应用的 Basic 凭证对该调用进行认证——参见 [Generate a User Access Token](/recipes/generate-user-access-token)。

您也可以在传递 `externalReferenceId` 的同时传入 `userId`/`accountId`，但它们必须与该外部引用 ID 解析到的用户相匹配。若不匹配，请求会被拒绝。

### 3. 使用它定位转账目标

当创建到另一个 Fluz 账户的钱包转账时（参见 [Transfer to Another Fluz Account](/features/transfer-to-another-fluz-wallet)），可以用外部引用 ID 来标识目标，而无需使用 Fluz 账户 ID：

```graphql theme={null}
mutation {
  createTransfer(input: {
    idempotencyKey: "1f7c5a2e-9b14-4c6d-8e3f-2a90d4b7c1aa"
    amount: 25.00
    destination: { externalReferenceId: "usr_8f3d2a91" }
  }) {
    transferId
  }
}
```

请提供 `destination.accountId` 或 `destination.externalReferenceId` 二选一——切勿同时提供。目标用户必须已授权您的应用；否则转账将被拒绝。

### 4. 将 webhook 事件匹配回您的用户

Webhook 载荷包含 `externalReferenceId`，因此您无需维护 Fluz ID 的查找表即可将 Fluz 事件与您自己的用户记录进行关联：

```json theme={null}
{
  "userId": "5070d5a1-d71a-4190-91b0-f116eec51771",
  "accountId": "9c2e1b44-7a3d-4f08-b6e5-d18a3c7f0e22",
  "externalReferenceId": "usr_8f3d2a91",
  "eventType": "DEPOSIT_COMPLETE",
  "amount": 100.00
}
```

有关 webhook 设置和投递的详细信息，请参见 [Configure App Widget](/developers/configure-app-widget)。

> 📘 **隐私说明**
>
> 当用户授权中没有关联外部引用 ID，或事件被标记为私有时，webhook 载荷中将省略 `externalReferenceId`。

## 校验规则与错误

| 场景                                                           | 结果                                                                                       |
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| 令牌请求既未提供 `externalReferenceId` 也未同时提供 `userId` + `accountId` | `Provide either externalReferenceId or both userId and accountId.`                       |
| 在您的应用中找不到对应的 `externalReferenceId`                           | `No user found with externalReferenceId <value>.`                                        |
| 与 `externalReferenceId` 一同提供的 `userId` 指向不同用户                | `Provided userId does not match the user associated with the externalReferenceId.`       |
| 与 `externalReferenceId` 一同提供的 `accountId` 指向不同账户             | `Provided accountId does not match the account associated with the externalReferenceId.` |
| 转账目标同时提供 `accountId` 和 `externalReferenceId`                 | `Provide either destination.accountId or destination.externalReferenceId, not both.`     |
| 转账目标用户尚未授权您的应用                                               | `Destination account has not authorized this application.`                               |
| 未提供外部引用 ID 即创建小部件会话                                          | `External reference ID is required for <type> applications`                              |

## 向现有授权添加外部引用 ID

如果某用户在您采用外部引用 ID 之前就已授权了您的应用，您可以在后续的授权或令牌请求中提供一个外部引用 ID，Fluz 将把它回填到现有授权上——前提是该授权尚未携带外部引用 ID。已有的外部引用 ID 永不会被覆盖。

## 外部引用 ID 不是什么

* 它**不是** Fluz 的 `userId` 或 `accountId`。这些是 Fluz 签发的 UUID；外部引用 ID 则由您签发。
* 它**不是**出现在提现记录或其他地方关联资金来源上的 `external_id` 或外部账户标识符。那些是对银行与处理方记录的引用，而非用户。\[TBD：确认这些是否在公共 schema 中暴露，并是否需要在此进行交叉引用]

<StickyContactSalesBanner />

<br />
