> ## 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.

# 引導並驗證企業

> 端到端跑通企業主路徑：設定一個僅限企業帳戶的應用程式、引導所有人完成 OAuth、註冊法人實體，並追蹤 KYB 直到企業帳戶獲核准。

本快速入門是面向企業版的[引導並連接客戶](/quickstart/onboard-customers)。你將設定一個只能落在企業帳戶上的應用程式，引導一位所有人走完 OAuth 授權，註冊其法人實體與實際受益人名單，追蹤 KYB 案件直到有結果，並透過在企業帳戶上發卡來證明連接已打通。

你面前的人始終首先是一個自然人。他以本人身分登入、以本人身分完成身分驗證，\_然後\_才註冊企業。下面的所有步驟都遵循這個順序。

<Info>
  **前置條件**

  * 一個**帶有 staging 應用程式的 Fluz 帳戶** —— 參見[準備你的帳戶](/get-started/prepare-accounts)與 [API 憑證](/get-started/api-credentials)。
  * 一個 `client_id`、一個 `client_secret` 與一個已註冊的 `redirect_uri` —— 參見[設定 OAuth 應用程式](/create-an-o-auth-app)。
  * 請求指向**沙盒** —— 沒有真實資金、沒有真實 PII。參見[Staging 與正式環境](/concepts/environments)。
</Info>

## 完整流程

<Steps>
  <Step title="為企業設定應用程式" icon="sliders">
    你的應用程式在 **Permissions** 分頁下有兩份權限清單，二者獨立編輯。

    | 清單                       | 應放入的內容                                                              |
    | :----------------------- | :------------------------------------------------------------------ |
    | **Permissions**          | 你的應用程式可以在**個人**帳戶上執行的操作。請包含**註冊企業**的權限 —— 該權限由個人帳戶授予，因此只屬於這裡，不屬於別處。 |
    | **Business permissions** | 企業帳戶一旦存在，你的應用程式可以在其上執行的操作。                                          |

    **Business permissions** 清單非空，才會讓你的應用程式啟用企業能力。留空的話，不管你還設定了什麼，使用者都不會看到申請企業帳戶的選項。

    趨還在應用程式編輯器裡，把你的 `redirect_uri` 註冊到 **OAuth** 分頁，並新增一個訂閱了 **KYB 狀態更新**的 webhook URL —— 這樣你不用輪詢就能知道審核已結束。

    <Warning>
      同意畫面是依據這兩份清單建置的，而不是依據你的 authorize URL。你沒有在此處勾選的權限，永遠不會展示給使用者，也永遠不會出現在 token 裡。完整說明：[OAuth 中的企業帳戶](/business-accounts-in-o-auth)。
    </Warning>
  </Step>

  <Step title="請 Fluz 將應用程式限制為僅企業帳戶" icon="building-lock">
    Fluz 可以為你的應用程式進行設定，使該流程永遠不會落在個人帳戶上。設定到位後，沒有企業帳戶的使用者會完全跳過帳戶選擇器，直接進入企業註冊。

    <Warning>
      **這一項不是自助的。** 請聯繫你的 Fluz 客戶經理，為你的應用程式啟用該限制。在此之前，沒有企業帳戶的使用者會同時看到自己的個人帳戶與申請企業帳戶的選項 —— 其中一些人會選個人帳戶。
    </Warning>

    如果你的應用程式確實同時服務消費者與企業，請跳過此步。提出這個要求，等於宣告落在個人帳戶上的授權對你而言永遠是一個 bug。
  </Step>

  <Step title="引導所有人完成 OAuth 授權" icon="plug">
    建置 authorize URL：

    ```text Authorization URL theme={null}
        https://uni.staging.fluzapp.com/authorize
          ?response_type=code
          &client_id=<YOUR_OAUTH_CLIENT_ID>
          &redirect_uri=<YOUR_REGISTERED_REDIRECT_URI>
          &state=<UNGUESSABLE_VALUE_YOU_STORED>
          &external_id=<YOUR_ID_FOR_THIS_ACCOUNT>
    ```

    在應用程式被限制為僅企業帳戶的情況下，首次進入的使用者會看到：登入與 2FA，然後是一個包含**兩組權限**的同意畫面 —— 現在授予的消費者權限，以及為其即將建立的企業預先核准的企業權限。該清單是唯讀的；使用者要麼全部接受，要麼無法完成。

    隨後使用者會被重新導向回你的 `redirect_uri`，並帶有 `?code=...&state=...`。先驗證 `state`，再在伺服器端擷取這個一次性的 `code`。

    <Tip>
      給**企業**分配它自己的 `external_id`，取自你系統裡的企業紀錄 —— 而不是取自所有人使用者。外部 ID 在首次使用時就會綁定到唯一一個 Fluz 帳戶，所以一個已經用在某人個人帳戶上的 ID，無法再用於他的企業。
    </Tip>

    完整參數參考：[面向客戶端的 OAuth 授權流程](/client-facing-o-auth-grant-flow)。
  </Step>

  <Step title="用授權碼交換申請人的 token" icon="key">
    與其他任何授權的交換過程相同 —— 使用 `client_id:client_secret` 的 base64 做基本認證：

    ```bash Exchange (cURL) theme={null}
        curl -X GET "https://uni.staging.fluzapp.com/token/exchange?code=<AUTH_CODE>&redirect_uri=<YOUR_REGISTERED_REDIRECT_URI>" \
          -H "Authorization: Basic <base64 of CLIENT_ID:CLIENT_SECRET>"
    ```

    `redirect_uri` 必須與你在 `/authorize` 使用的完全一致（逐位元組相同）。

    <Note>
      企業此時尚不存在，因此這個 token 屬於申請人的**個人**帳戶 —— 這是正確的，也正是 `registerBusiness` 所需要的 token。請從交換回應中讀取帳戶並持久化，而不要根據你自己關於「誰發起了流程」的紀錄去推斷。
    </Note>
  </Step>

  <Step title="驗證申請人身分（KYC）" icon="id-card">
    KYB 驗證的是企業與\_其他\_所有人。它不驗證申請人，所以申請人必須在你註冊任何東西之前就已通過驗證 —— 否則註冊會以 `ARG-0001` 失敗。

    使用申請人的 token 呼叫 `verifyUserInformation`。在 staging 環境中，這個測試身分始終回傳 `APPROVED`：

    <CodeGroup>
      ```graphql Mutation theme={null}
          mutation VerifyUserInformation(
            $firstName: String!
            $lastName: String!
            $streetLine1: String!
            $city: String!
            $state: String!
            $postalCode: String!
            $country: String!
            $dateOfBirth: String!
            $ssnLast4: String!
          ) {
            verifyUserInformation(
              firstName: $firstName
              lastName: $lastName
              streetLine1: $streetLine1
              city: $city
              state: $state
              postalCode: $postalCode
              country: $country
              dateOfBirth: $dateOfBirth
              ssnLast4: $ssnLast4
            ) {
              status
              message
            }
          }
      ```

      ```json Variables (approved test identity) theme={null}
          {
            "firstName": "John",
            "lastName": "Smith",
            "streetLine1": "222333 Peachtree Place",
            "city": "Atlanta",
            "state": "GA",
            "postalCode": "30318",
            "country": "United States",
            "dateOfBirth": "02/28/1975",
            "ssnLast4": "3333"
          }
      ```
    </CodeGroup>

    申請人需要哪一種檢查，取決於你在下一步為他填寫的 `isUsPerson`：`true` 要求檔案中已有一次成功的 SSN（CIP）驗證，`false` 要求一次成功的文件驗證。參見[使用者 KYC 驗證](/user-kyc-verification)與[測試 KYC 流程](/test-kyc-flows)。

    <Warning>
      同一使用者最多可提交 **3 次**，之後將回傳 `ERROR`。不要把嘗試次數浪費在你即將用作申請人的那個使用者身上。
    </Warning>
  </Step>

  <Step title="註冊企業" icon="building">
    先解析該實體所屬的經營類別 —— 千萬不要把這些 UUID 寫死：

    ```graphql theme={null}
        query {
          getBusinessCategories {
            id
            name
            subCategories { id name }
          }
        }
    ```

    然後在一次呼叫中提交實體資訊與完整的所有人名單，仍然使用申請人的**個人帳戶** token：

    <CodeGroup>
      ```graphql Mutation theme={null}
          mutation RegisterBusiness($input: RegisterBusinessInput!) {
            registerBusiness(input: $input) {
              accountId
              kybStatus
              success
              error { code message }
            }
          }
      ```

      ```json Variables theme={null}
          {
            "input": {
              "businessName": "Acme Corporation",
              "dbaName": "Acme Co",
              "businessStructure": "LLC",
              "businessLegalAddress": {
                "streetAddressLine1": "123 Main Street",
                "city": "San Francisco",
                "state": "California",
                "postalCode": "94102",
                "country": "United States"
              },
              "stateOfIncorporation": "California",
              "taxId": "12-3456789",
              "businessCategoryId": "<FROM_getBusinessCategories>",
              "businessSubCategoryId": "<FROM_getBusinessCategories>",
              "natureOfBusiness": "E-commerce retail",
              "businessAccountUsage": ["CORPORATE_SPENDING_ADMIN"],
              "externalReferenceId": "your-business-id-123",
              "confirm": {
                "allOwnersWith25PercentageOwnershipListed": true,
                "noOwnersMoreThan25Percentage": false
              },
              "owners": [
                {
                  "firstName": "John",
                  "lastName": "Smith",
                  "emailAddress": "john@example.com",
                  "phoneNumber": "+14155551234",
                  "title": "Chief Executive Officer",
                  "ownershipPercentage": 100,
                  "isControlPerson": true,
                  "isInvited": false,
                  "isUsPerson": true
                }
              ]
            }
          }
      ```
    </CodeGroup>

    成功的回應會回傳一個 `accountId` 與值為 `SUBMITTED` 的 `kybStatus`。請立刻保存 `accountId` —— 它是你掌握這份申請的唯一句柄。

    三件最常導致首次提交被拒的事：

    * **每一位所有人都必須填寫 `isUsPerson`**，包括申請人與受邀所有人。這是名單被拒最常見的原因。
    * **必須恰好有一位所有人是申請人** —— 透過 email 或電話與 token 所屬使用者比對 —— 且必須恰好有一位是控制人。
    * **法定地址會經過地址驗證服務商核驗。** 編造的街道會以 `BS-0002` 失敗；請使用[測試地址](/test-addresses)。

    <Warning>
      錯誤是**放在回應 payload 內部**回傳的，而不是作為 GraphQL 錯誤 —— 請根據 `success` 與 `error` 物件分支處理。完整的參數與錯誤參考：[註冊企業](/business-registration)。
    </Warning>
  </Step>

  <Step title="讓其餘所有人完成驗證，然後等待" icon="users">
    `SUBMITTED` 表示 payload 通過了驗證並且案件已建立。它不表示已獲核准。

    產生一個**企業帳戶** token —— 用申請人的 `userId` 與新企業的 `accountId` 呼叫 `generateUserAccessToken` —— 然後讀取所有人名單：

    ```graphql theme={null}
        query GetBusiness {
          getBusiness {
            accountId
            kybStatus
            owners { id name verificationType status }
          }
        }
    ```

    走文件路徑的所有人可透過 [requestOwnerDocumentVerificationLink](/owner-verification-link) 取得連結；被你標記為 `isInvited: true` 的所有人由 Fluz 寄 email 邀請並自行完成驗證。持續追蹤，直到 `kybStatus` 為終態**且**每位所有人都回報 `READY`。

    狀態會從 `PENDING` 變為 `APPROVED` 或 `DECLINED`，通常在一到兩個工作天內。請從你在第 1 步設定的 **KYB 狀態更新** webhook 取得結果，並用 `getBusiness` 做對帳 —— 每小時一次即可，不要每次頁面載入都查。

    <Note>
      向使用者如實展示「審核中」的狀態。不要把他丟進一個還不能交易的企業後台，也不要在被拒後自動重試 —— 第二次提交會被 `BS-0007` 阻擋。完整生命週期：[註冊企業](/business-registration)。
    </Note>
  </Step>

  <Step title="在企業帳戶上操作 —— 證明它" icon="credit-card">
    一旦 `kybStatus` 變為 `APPROVED`，用**企業帳戶** token 執行任何 Fluz 操作，它就會針對該企業執行。沒有單獨的企業 API。

    ```graphql theme={null}
        mutation {
          createVirtualCard(
            input: {
              idempotencyKey: "9f2c4d61-77aa-4b0e-8f2a-1c9d3e5b7a04"
              offerId: "ed669305-5e43-40a0-9a25-7a15ed174628"
              spendLimit: 250.00
              lockCardNextUse: true
              cardNickname: "First card on a verified business"
            }
          ) {
            virtualCardId
            virtualCardLast4
            status
          }
        }
    ```

    回傳一張 `ACTIVE` 卡片，意味著閃環已完成：已設定 → 已授權 → 已驗證 → 已註冊 → 已核准 → 可操作。
  </Step>
</Steps>

## 大功告成 🎉

你已經把一家企業從一個空白應用程式帶到了可以消費的已驗證帳戶。接下來：

<CardGroup cols={2}>
  <Card title="OAuth 中的企業帳戶" icon="building-lock" href="/business-accounts-in-o-auth">
    兩份權限清單、帳戶選擇器，以及授權碼最終解析到哪個帳戶。
  </Card>

  <Card title="註冊企業" icon="clipboard-check" href="/business-registration">
    前置條件、KYB 狀態生命週期，以及如何追蹤案件直到有結果。
  </Card>

  <Card title="提交企業文件" icon="file-arrow-up" href="/submit-business-documents">
    授權簽署人文件上傳，以及如何回應補件要求。
  </Card>

  <Card title="引導並連接客戶" icon="user-plus" href="/quickstart/onboard-customers">
    面向個人的同一段旅程。
  </Card>
</CardGroup>

<Note>
  **想瞭解更多？** 透過 [support@fluz.app](mailto:support@fluz.app) 聯繫我們，與專家討論或申請示範。
</Note>
